2007-09-06 Joel Sherrill <joel.sherrill@oarcorp.com>

* libcsupport/Makefile.am, libcsupport/src/printk.c:
	* libcsupport/src/printk_plugin.c: New file.
	include/rtems/bspIo.h, libmisc/cpuuse/cpuusagereport.c,
	libmisc/cpuuse/cpuuse.h, libmisc/stackchk/check.c,
	libmisc/stackchk/stackchk.h: rtems/include/rtems/rtems/ratemon.h,
	rtems/src/ratemonreportstatistics.c: Added capability to specify
	your own "printf" routine to various reporting functions.  This
	added an XXX_with_plugin as the underlying implementation for
	  + rtems_rate_monotonic_report_statistics
	  + rtems_stack_checker_report_usage
	  + rtems_cpu_usage_report
	As demonstration, the http netdemo can now print out stack
	and cpu usage reports.
This commit is contained in:
Joel Sherrill
2007-09-06 22:51:25 +00:00
parent 9af457f4d7
commit 90a5d194a2
11 changed files with 210 additions and 53 deletions

View File

@@ -1,3 +1,19 @@
2007-09-06 Joel Sherrill <joel.sherrill@oarcorp.com>
* libcsupport/Makefile.am, libcsupport/src/printk.c:
* libcsupport/src/printk_plugin.c: New file.
include/rtems/bspIo.h, libmisc/cpuuse/cpuusagereport.c,
libmisc/cpuuse/cpuuse.h, libmisc/stackchk/check.c,
libmisc/stackchk/stackchk.h: rtems/include/rtems/rtems/ratemon.h,
rtems/src/ratemonreportstatistics.c: Added capability to specify
your own "printf" routine to various reporting functions. This
added an XXX_with_plugin as the underlying implementation for
+ rtems_rate_monotonic_report_statistics
+ rtems_stack_checker_report_usage
+ rtems_cpu_usage_report
As demonstration, the http netdemo can now print out stack
and cpu usage reports.
2007-09-06 Joel Sherrill <joel.sherrill@oarcorp.com> 2007-09-06 Joel Sherrill <joel.sherrill@oarcorp.com>
* shttpd/compat_rtems.c: Style clean up. * shttpd/compat_rtems.c: Style clean up.

View File

@@ -37,8 +37,25 @@ extern BSP_polling_getchar_function_type BSP_poll_char;
* and initialisation of the previous variable are done. * and initialisation of the previous variable are done.
*/ */
#include <stdarg.h> #include <stdarg.h>
extern void vprintk(char *fmt, va_list ap);
extern void printk(char *fmt, ...); extern void vprintk(const char *fmt, va_list ap);
extern void printk(const char *fmt, ...);
/*
* This routine is passed into RTEMS reporting functions
* that may have their output redirected. In particular,
* the cpu usage, period usage, and stack usage reporting
* functions use this. If the user provides their
* own "printf plugin", then they may redirect those reports
* as they see fit.
*/
extern int printk_plugin(void *context, const char *fmt, ...);
/*
* Type definition for function which can be plugged in to
* certain reporting routines to redirect the output
*/
typedef int (*rtems_printk_plugin_t)(void *, const char *format, ...);
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@@ -84,9 +84,9 @@ LIBC_GLUE_C_FILES = src/__getpid.c src/__gettod.c src/__times.c \
BSD_LIBC_C_FILES = src/strlcpy.c src/strlcat.c BSD_LIBC_C_FILES = src/strlcpy.c src/strlcat.c
libcsupport_a_SOURCES = src/gxx_wrappers.c src/printk.c $(BSD_LIBC_C_FILES) \ libcsupport_a_SOURCES = src/gxx_wrappers.c src/printk.c src/printk_plugin.c \
$(BASE_FS_C_FILES) $(MALLOC_C_FILES) $(ERROR_C_FILES) \ $(BSD_LIBC_C_FILES) $(BASE_FS_C_FILES) $(MALLOC_C_FILES) \
$(ASSOCIATION_C_FILES) $(ERROR_C_FILES) $(ASSOCIATION_C_FILES)
if UNIX if UNIX
libcsupport_a_SOURCES += src/unixlibc.c src/unixlibc_io.c src/hosterr.c libcsupport_a_SOURCES += src/unixlibc.c src/unixlibc_io.c src/hosterr.c

View File

@@ -1,22 +1,21 @@
/*-------------------------------------------------------------------------+ /*
| printk.c v1.1 - PC386 BSP - 1997/08/07 *
+--------------------------------------------------------------------------+ * (C) Copyright 1997 -
| (C) Copyright 1997 - * - NavIST Group - Real-Time Distributed Systems and Industrial Automation
| - NavIST Group - Real-Time Distributed Systems and Industrial Automation *
| * http://pandora.ist.utl.pt
| http://pandora.ist.utl.pt *
| * Instituto Superior Tecnico * Lisboa * PORTUGAL
| Instituto Superior Tecnico * Lisboa * PORTUGAL *
+--------------------------------------------------------------------------+ * Disclaimer:
| Disclaimer: *
| * This file is provided "AS IS" without warranty of any kind, either
| This file is provided "AS IS" without warranty of any kind, either * expressed or implied.
| expressed or implied. *--------------------------------------------------------------------------+
+--------------------------------------------------------------------------+ * This code is based on code by: Jose Rufino - IST
| This code is based on code by: Jose Rufino - IST *
| * $Id$
| $Id$ *--------------------------------------------------------------------------*/
+--------------------------------------------------------------------------*/
#if HAVE_CONFIG_H #if HAVE_CONFIG_H
#include "config.h" #include "config.h"
@@ -71,7 +70,7 @@ printNum(long unsigned int num, int base, int sign, int maxwidth, int lead)
| Returns: Nothing. | Returns: Nothing.
+--------------------------------------------------------------------------*/ +--------------------------------------------------------------------------*/
void void
vprintk(char *fmt, va_list ap) vprintk(const char *fmt, va_list ap)
{ {
char c, *str; char c, *str;
int lflag, base, sign, width, lead; int lflag, base, sign, width, lead;
@@ -138,7 +137,7 @@ vprintk(char *fmt, va_list ap)
} /* vprintk */ } /* vprintk */
void void
printk(char *fmt, ...) printk(const char *fmt, ...)
{ {
va_list ap; /* points to each unnamed argument in turn */ va_list ap; /* points to each unnamed argument in turn */

View File

@@ -0,0 +1,33 @@
/*
* COPYRIGHT (c) 1989-2007.
* On-Line Applications Research Corporation (OAR).
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
* http://www.rtems.com/license/LICENSE.
*
* $Id$
*/
#if HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdarg.h>
#include <rtems/bspIo.h>
int printk_plugin(
void *ignored,
const char *format,
...
)
{
va_list arg_pointer;
va_start (arg_pointer, format);
vprintk( format, arg_pointer );
return 0;
}

View File

@@ -27,8 +27,7 @@
#include <rtems/cpuuse.h> #include <rtems/cpuuse.h>
#include <rtems/bspIo.h> #include <rtems/bspIo.h>
#if defined(RTEMS_ENABLE_NANOSECOND_RATE_MONOTONIC_STATISTICS) || \ #if defined(RTEMS_ENABLE_NANOSECOND_CPU_USAGE_STATISTICS)
defined(RTEMS_ENABLE_NANOSECOND_CPU_USAGE_STATISTICS)
#include <rtems/score/timespec.h> #include <rtems/score/timespec.h>
#endif #endif
@@ -43,7 +42,10 @@
* rtems_cpu_usage_report * rtems_cpu_usage_report
*/ */
void rtems_cpu_usage_report( void ) void rtems_cpu_usage_report_with_plugin(
void *context,
rtems_printk_plugin_t print
)
{ {
uint32_t i; uint32_t i;
uint32_t api_index; uint32_t api_index;
@@ -57,6 +59,9 @@ void rtems_cpu_usage_report( void )
uint32_t total_units = 0; uint32_t total_units = 0;
#endif #endif
if ( !print )
return;
/* /*
* When not using nanosecond CPU usage resolution, we have to count * When not using nanosecond CPU usage resolution, we have to count
* the number of "ticks" we gave credit for to give the user a rough * the number of "ticks" we gave credit for to give the user a rough
@@ -81,7 +86,10 @@ void rtems_cpu_usage_report( void )
} }
#endif #endif
printk( "CPU Usage by thread\n" #if defined(RTEMS_ENABLE_NANOSECOND_CPU_USAGE_STATISTICS)
(*print)( context, "--- CPU Usage times are seconds:microseconds ---\n" );
#endif
(*print)( context, "CPU Usage by thread\n"
#ifdef RTEMS_ENABLE_NANOSECOND_CPU_USAGE_STATISTICS #ifdef RTEMS_ENABLE_NANOSECOND_CPU_USAGE_STATISTICS
" ID NAME SECONDS PERCENT\n" " ID NAME SECONDS PERCENT\n"
#else #else
@@ -104,7 +112,7 @@ void rtems_cpu_usage_report( void )
rtems_object_get_name( the_thread->Object.id, sizeof(name), name ); rtems_object_get_name( the_thread->Object.id, sizeof(name), name );
printk( "0x%08" PRIx32 " %4s ", the_thread->Object.id, name ); (*print)( context, "0x%08" PRIx32 " %4s ", the_thread->Object.id, name );
#ifdef RTEMS_ENABLE_NANOSECOND_CPU_USAGE_STATISTICS #ifdef RTEMS_ENABLE_NANOSECOND_CPU_USAGE_STATISTICS
/* /*
@@ -124,7 +132,9 @@ void rtems_cpu_usage_report( void )
/* /*
* Print the information * Print the information
*/ */
printk("%2" PRId32 ".%06" PRId32 " %3" PRId32 ".%02" PRId32 "\n",
(*print)( context,
"%2" PRId32 ":%06" PRId32 " %3" PRId32 ".%02" PRId32 "\n",
ran.tv_sec, ran.tv_nsec / TOD_NANOSECONDS_PER_MICROSECOND, ran.tv_sec, ran.tv_nsec / TOD_NANOSECONDS_PER_MICROSECOND,
ival, fval ival, fval
); );
@@ -133,7 +143,7 @@ void rtems_cpu_usage_report( void )
the_thread->ticks_executed * 10000 / total_units : 0; the_thread->ticks_executed * 10000 / total_units : 0;
fval = ival % 100; fval = ival % 100;
ival /= 100; ival /= 100;
printk( (*print)( context,
"%8" PRId32 " %3" PRId32 ".%02" PRId32"\n", "%8" PRId32 " %3" PRId32 ".%02" PRId32"\n",
the_thread->ticks_executed, the_thread->ticks_executed,
ival, ival,
@@ -145,16 +155,21 @@ void rtems_cpu_usage_report( void )
} }
#ifdef RTEMS_ENABLE_NANOSECOND_CPU_USAGE_STATISTICS #ifdef RTEMS_ENABLE_NANOSECOND_CPU_USAGE_STATISTICS
printk( "Time since last CPU Usage reset %" PRId32 (*print)( context, "Time since last CPU Usage reset %" PRId32
".%06" PRId32 " seconds\n", ".%06" PRId32 " seconds\n",
total.tv_sec, total.tv_sec,
total.tv_nsec / TOD_NANOSECONDS_PER_MICROSECOND total.tv_nsec / TOD_NANOSECONDS_PER_MICROSECOND
); );
#else #else
printk( (*print)( context,
"Ticks since last reset = %" PRId32 "\n", "Ticks since last reset = %" PRId32 "\n",
_Watchdog_Ticks_since_boot - CPU_usage_Ticks_at_last_reset _Watchdog_Ticks_since_boot - CPU_usage_Ticks_at_last_reset
); );
printk( "Total Units = %" PRId32 "\n\n", total_units ); (*print)( context, "Total Units = %" PRId32 "\n\n", total_units );
#endif #endif
} }
void rtems_cpu_usage_report( void )
{
rtems_cpu_usage_report_with_plugin( NULL, printk_plugin );
}

View File

@@ -3,7 +3,7 @@
* This include file contains information necessary to utilize * This include file contains information necessary to utilize
* and install the cpu usage reporting mechanism. * and install the cpu usage reporting mechanism.
* *
* COPYRIGHT (c) 1989-2006. * COPYRIGHT (c) 1989-2007.
* On-Line Applications Research Corporation (OAR). * On-Line Applications Research Corporation (OAR).
* *
* The license and distribution terms for this file may be * The license and distribution terms for this file may be
@@ -16,10 +16,21 @@
#ifndef __RTEMS_CPUUSE_h #ifndef __RTEMS_CPUUSE_h
#define __RTEMS_CPUUSE_h #define __RTEMS_CPUUSE_h
#include <rtems/bspIo.h>
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
/*
* rtems_cpu_usage_report_with_handler
*/
void rtems_cpu_usage_report_with_plugin(
void *context,
rtems_printk_plugin_t handler
);
/* /*
* rtems_cpu_usage_report * rtems_cpu_usage_report
*/ */

View File

@@ -351,10 +351,13 @@ void *Stack_check_find_high_water_mark(
} }
/* /*
* Stack_check_Dump_threads_usage( * Stack_check_Dump_threads_usage
* *
* Try to print out how much stack was actually used by the task. * Try to print out how much stack was actually used by the task.
*/ */
static void *print_context;
static rtems_printk_plugin_t print_handler;
void Stack_check_Dump_threads_usage( void Stack_check_Dump_threads_usage(
Thread_Control *the_thread Thread_Control *the_thread
) )
@@ -368,6 +371,9 @@ void Stack_check_Dump_threads_usage(
if ( !the_thread ) if ( !the_thread )
return; return;
if ( !print_handler )
return;
/* /*
* XXX HACK to get to interrupt stack * XXX HACK to get to interrupt stack
*/ */
@@ -402,7 +408,9 @@ void Stack_check_Dump_threads_usage(
name[ 4 ] = '\0'; name[ 4 ] = '\0';
} }
printk("0x%08" PRIx32 " %4s 0x%p - 0x%p %8" PRId32 " %8" PRId32 "\n", (*print_handler)(
print_context,
"0x%08" PRIx32 " %4s 0x%p - 0x%p %8" PRId32 " %8" PRId32 "\n",
the_thread ? the_thread->Object.id : ~0, the_thread ? the_thread->Object.id : ~0,
name, name,
stack->area, stack->area,
@@ -432,13 +440,19 @@ void Stack_check_Dump_threads_usage(
* rtems_stack_checker_report_usage * rtems_stack_checker_report_usage
*/ */
void rtems_stack_checker_report_usage( void ) void rtems_stack_checker_report_usage_with_plugin(
void *context,
rtems_printk_plugin_t print
)
{ {
if (Stack_check_Initialized == 0) if (Stack_check_Initialized == 0)
return; return;
printk("Stack usage by thread\n"); print_context = context;
printk( print_handler = print;
(*print)( context, "Stack usage by thread\n");
(*print)( context,
" ID NAME LOW HIGH AVAILABLE USED\n" " ID NAME LOW HIGH AVAILABLE USED\n"
); );
@@ -447,4 +461,13 @@ void rtems_stack_checker_report_usage( void )
/* dump interrupt stack info if any */ /* dump interrupt stack info if any */
Stack_check_Dump_threads_usage((Thread_Control *) -1); Stack_check_Dump_threads_usage((Thread_Control *) -1);
print_context = NULL;
print_handler = NULL;
}
void rtems_stack_checker_report_usage( void )
{
rtems_stack_checker_report_usage_with_plugin( NULL, printk_plugin );
} }

View File

@@ -18,6 +18,8 @@
#ifndef __RTEMS_STACK_CHECKER_h #ifndef __RTEMS_STACK_CHECKER_h
#define __RTEMS_STACK_CHECKER_h #define __RTEMS_STACK_CHECKER_h
#include <rtems/bspIo.h>
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
@@ -42,6 +44,21 @@ boolean rtems_stack_checker_is_blown( void );
*/ */
void rtems_stack_checker_report_usage( void ); void rtems_stack_checker_report_usage( void );
/** @brief Print Stack Usage Report
*
* This method prints a stack usage report for the curently executing
* task.
*
* @param[in] context is the context to pass to the print handler
* @param[in] print is the print handler
*
* @note It uses the CALLER's routine to print the report.
*/
void rtems_stack_checker_report_usage_with_plugin(
void *context,
rtems_printk_plugin_t print
);
/************************************************************* /*************************************************************
************************************************************* *************************************************************
** Prototyped only so the user extension can be installed ** ** Prototyped only so the user extension can be installed **

View File

@@ -32,6 +32,8 @@
#define RTEMS_RATEMON_EXTERN extern #define RTEMS_RATEMON_EXTERN extern
#endif #endif
#include <rtems/bspIo.h>
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
@@ -273,6 +275,19 @@ rtems_status_code rtems_rate_monotonic_reset_statistics(
*/ */
void rtems_rate_monotonic_reset_all_statistics( void ); void rtems_rate_monotonic_reset_all_statistics( void );
/*
* rtems_rate_monotonic_report_statistics
*
* DESCRIPTION:
*
* This directive allows a thread to print the statistics information
* on ALL period instances which have non-zero counts using printk.
*/
void rtems_rate_monotonic_report_statistics_with_plugin(
void *context,
rtems_printk_plugin_t print
);
/* /*
* rtems_rate_monotonic_report_statistics * rtems_rate_monotonic_report_statistics
* *

View File

@@ -40,7 +40,10 @@
* inside and outside of RTEMS. It is presented as part of the Manager * inside and outside of RTEMS. It is presented as part of the Manager
* but actually uses other services of the Manager. * but actually uses other services of the Manager.
*/ */
void rtems_rate_monotonic_report_statistics( void ) void rtems_rate_monotonic_report_statistics_with_plugin(
void *context,
rtems_printk_plugin_t print
)
{ {
rtems_status_code status; rtems_status_code status;
rtems_id id; rtems_id id;
@@ -48,13 +51,16 @@ void rtems_rate_monotonic_report_statistics( void )
rtems_rate_monotonic_period_status the_status; rtems_rate_monotonic_period_status the_status;
char name[5]; char name[5];
printk( "Period information by period\n" ); if ( !print )
return;
(*print)( context, "Period information by period\n" );
#if defined(RTEMS_ENABLE_NANOSECOND_RATE_MONOTONIC_STATISTICS) #if defined(RTEMS_ENABLE_NANOSECOND_RATE_MONOTONIC_STATISTICS)
printk( "--- Period times are seconds:microseconds ---\n" ); (*print)( context, "--- Period times are seconds:microseconds ---\n" );
#endif #endif
#if defined(RTEMS_ENABLE_NANOSECOND_CPU_USAGE_STATISTICS) #if defined(RTEMS_ENABLE_NANOSECOND_CPU_USAGE_STATISTICS)
printk( "--- CPU Usage times are seconds:microseconds ---\n" ); (*print)( context, "--- CPU Usage times are seconds:microseconds ---\n" );
#endif #endif
/* /*
Layout by columns -- in memory of Hollerith :) Layout by columns -- in memory of Hollerith :)
@@ -66,10 +72,10 @@ ididididid NNNN ccccc mmmmmm X
Uncomment the following if you are tinkering with the formatting. Uncomment the following if you are tinkering with the formatting.
Be sure to test the various cases. Be sure to test the various cases.
*/ */
printk("\ (*print)( context,"\
1234567890123456789012345678901234567890123456789012345678901234567890123456789\ 1234567890123456789012345678901234567890123456789012345678901234567890123456789\
\n"); \n");
printk( " ID OWNER COUNT MISSED CPU TIME " (*print)( context, " ID OWNER COUNT MISSED CPU TIME "
#ifdef RTEMS_ENABLE_NANOSECOND_CPU_USAGE_STATISTICS #ifdef RTEMS_ENABLE_NANOSECOND_CPU_USAGE_STATISTICS
" " " "
#endif #endif
@@ -108,7 +114,7 @@ ididididid NNNN ccccc mmmmmm X
* Print part of report line that is not dependent on granularity * Print part of report line that is not dependent on granularity
*/ */
printk( (*print)( context,
"0x%08" PRIx32 " %4s %5" PRId32 " %6" PRId32 " ", "0x%08" PRIx32 " %4s %5" PRId32 " %6" PRId32 " ",
id, name, id, name,
the_stats.count, the_stats.missed_count the_stats.count, the_stats.missed_count
@@ -126,7 +132,7 @@ ididididid NNNN ccccc mmmmmm X
the_stats.count, the_stats.count,
&cpu_average &cpu_average
); );
printk( (*print)( context,
"%" PRId32 ":" NANOSECONDS_FMT "/" /* min cpu time */ "%" PRId32 ":" NANOSECONDS_FMT "/" /* min cpu time */
"%" PRId32 ":" NANOSECONDS_FMT "/" /* max cpu time */ "%" PRId32 ":" NANOSECONDS_FMT "/" /* max cpu time */
"%" PRId32 ":" NANOSECONDS_FMT " ", /* avg cpu time */ "%" PRId32 ":" NANOSECONDS_FMT " ", /* avg cpu time */
@@ -144,7 +150,7 @@ ididididid NNNN ccccc mmmmmm X
fval_cpu = ival_cpu % 100; fval_cpu = ival_cpu % 100;
ival_cpu /= 100; ival_cpu /= 100;
printk( (*print)( context,
"%3" PRId32 "/%4" PRId32 "/%3" PRId32 ".%02" PRId32 " ", "%3" PRId32 "/%4" PRId32 "/%3" PRId32 ".%02" PRId32 " ",
the_stats.min_cpu_time, the_stats.max_cpu_time, ival_cpu, fval_cpu the_stats.min_cpu_time, the_stats.max_cpu_time, ival_cpu, fval_cpu
); );
@@ -162,7 +168,7 @@ ididididid NNNN ccccc mmmmmm X
the_stats.count, the_stats.count,
&wall_average &wall_average
); );
printk( (*print)( context,
"%" PRId32 ":" PERCENT_FMT "/" /* min wall time */ "%" PRId32 ":" PERCENT_FMT "/" /* min wall time */
"%" PRId32 ":" PERCENT_FMT "/" /* max wall time */ "%" PRId32 ":" PERCENT_FMT "/" /* max wall time */
"%" PRId32 ":" PERCENT_FMT "\n", /* avg wall time */ "%" PRId32 ":" PERCENT_FMT "\n", /* avg wall time */
@@ -179,7 +185,7 @@ ididididid NNNN ccccc mmmmmm X
ival_wall = the_stats.total_wall_time * 100 / the_stats.count; ival_wall = the_stats.total_wall_time * 100 / the_stats.count;
fval_wall = ival_wall % 100; fval_wall = ival_wall % 100;
ival_wall /= 100; ival_wall /= 100;
printk( (*print)( context,
"%3" PRId32 "/%4" PRId32 "/%3" PRId32 ".%02" PRId32 "\n", "%3" PRId32 "/%4" PRId32 "/%3" PRId32 ".%02" PRId32 "\n",
the_stats.min_wall_time, the_stats.max_wall_time, ival_wall, fval_wall the_stats.min_wall_time, the_stats.max_wall_time, ival_wall, fval_wall
); );
@@ -187,3 +193,8 @@ ididididid NNNN ccccc mmmmmm X
} }
} }
} }
void rtems_rate_monotonic_report_statistics( void )
{
rtems_rate_monotonic_report_statistics_with_plugin( NULL, printk_plugin );
}