[PATCH] libmisc/cpuuse: Top support for current load.
Gedare Bloom
gedare at rtems.org
Tue Apr 28 13:46:36 UTC 2015
Is there user-facing documentation for this that should be updated?
On Mon, Apr 27, 2015 at 7:08 PM, Chris Johns <chrisj at rtems.org> wrote:
> The cpuuse top command now supports the current load where the list of
> tasks is ordered based on the current load rather than the total cpu usage.
> This lets you see what is using the processor at any specific instance. You
> can toggle between the modes.
>
> Added memory usage stats for unified and separate workspace and C heaps as
> well as displaying the allocated stack space.
>
> Added a few more command keys to refresh the display, show all tasks in the
> system, control the lines display and a scrolling mode that does not clear
> the display on each refresh.
>
> Removed support for tick kernel builds. The tick support in the kernel is to
> be removed.
> ---
> cpukit/libmisc/cpuuse/cpuusagetop.c | 691 ++++++++++++++++++++++++++----------
> 1 file changed, 496 insertions(+), 195 deletions(-)
>
> diff --git a/cpukit/libmisc/cpuuse/cpuusagetop.c b/cpukit/libmisc/cpuuse/cpuusagetop.c
> index e47ba59..13b659e 100644
> --- a/cpukit/libmisc/cpuuse/cpuusagetop.c
> +++ b/cpukit/libmisc/cpuuse/cpuusagetop.c
> @@ -18,6 +18,7 @@
> #include "config.h"
> #endif
>
> +#include <stdbool.h>
> #include <string.h>
> #include <stdlib.h>
> #include <stdio.h>
> @@ -25,29 +26,97 @@
> #include <inttypes.h>
>
> #include <rtems/cpuuse.h>
> +#include <rtems/malloc.h>
> #include <rtems/score/objectimpl.h>
> +#include <rtems/score/protectedheap.h>
> #include <rtems/score/threadimpl.h>
> #include <rtems/score/todimpl.h>
> #include <rtems/score/watchdogimpl.h>
> +#include <rtems/score/wkspace.h>
>
> /*
> * Common variable to sync the load monitor task.
> */
> -static volatile int rtems_cpuusage_top_thread_active;
> -
> -typedef struct {
> - void *context;
> +typedef struct
> +{
> + void* context;
> rtems_printk_plugin_t print;
> -}rtems_cpu_usage_plugin_t;
> +} rtems_cpu_usage_plugin;
> +
> +/*
> + * Use a struct for all data to allow more than one top and to support the
> + * thread iterator.
> + */
> +typedef struct
> +{
> + volatile bool thread_run;
> + volatile bool thread_active;
> + volatile bool single_page;
> + volatile bool sort_current;
> + volatile uint32_t poll_rate_usecs;
> + volatile uint32_t show;
> + rtems_cpu_usage_plugin plugin;
> + Thread_CPU_usage_t zero;
> + Timestamp_Control uptime;
> + Timestamp_Control last_uptime;
> + Timestamp_Control period;
> + int task_count; /* Number of tasks. */
> + int last_task_count; /* Number of tasks in the previous sample. */
> + int task_size; /* The size of the arrays */
> + Thread_Control** tasks; /* List of tasks in this sample. */
> + Thread_Control** last_tasks; /* List of tasks in the last sample. */
> + Thread_CPU_usage_t* usage; /* Usage of task's in this sample. */
> + Thread_CPU_usage_t* last_usage; /* Usage of task's in the last sample. */
> + Thread_CPU_usage_t* current_usage; /* Current usage for this sample. */
> + Timestamp_Control total; /* Total run run, should equal the uptime. */
> + Timestamp_Control idle; /* Time spent in idle. */
> + Timestamp_Control current; /* Current time run in this period. */
> + Timestamp_Control current_idle; /* Current time in idle this period. */
> + uint32_t stack_size; /* Size of stack allocated. */
> +} rtems_cpu_usage_data;
> +
> +/*
> + * Private version of the iterator with an arg. This will be moved
> + * to the public in 5.0.
> + */
> +
> +typedef void (*rtems_per_thread_routine_2)( Thread_Control *, void* );
>
> -#define RTEMS_CPUUSAGE_TOP_MAX_LOAD_TASKS (20)
> +void rtems_iterate_over_all_threads_2(rtems_per_thread_routine_2 routine,
> + void* arg);
>
> +void rtems_iterate_over_all_threads_2(rtems_per_thread_routine_2 routine,
> + void* arg)
> +{
> + uint32_t i;
> + uint32_t api_index;
> + Thread_Control *the_thread;
> + Objects_Information *information;
> +
> + if ( !routine )
> + return;
> +
> + for ( api_index = 1 ; api_index <= OBJECTS_APIS_LAST ; api_index++ ) {
> + #if !defined(RTEMS_POSIX_API) || defined(RTEMS_DEBUG)
> + if ( !_Objects_Information_table[ api_index ] )
> + continue;
> + #endif
> + information = _Objects_Information_table[ api_index ][ 1 ];
> + if ( information ) {
> + for ( i=1 ; i <= information->maximum ; i++ ) {
> + the_thread = (Thread_Control *)information->local_table[ i ];
> + if ( the_thread )
> + (*routine)(the_thread, arg);
> + }
> + }
> + }
> +}
>
> static inline bool equal_to_uint32_t( uint32_t * lhs, uint32_t * rhs )
> {
> if ( *lhs == *rhs )
> return true;
> - else
> + else
> return false;
> }
>
> @@ -60,31 +129,163 @@ static inline bool less_than_uint32_t( uint32_t * lhs, uint32_t * rhs )
> }
>
> #ifndef __RTEMS_USE_TICKS_FOR_STATISTICS__
> - #define _Thread_CPU_usage_Equal_to( _lhs, _rhs ) \
> + #define CPU_usage_Equal_to( _lhs, _rhs ) \
> _Timestamp_Equal_to( _lhs, _rhs )
> #else
> - #define _Thread_CPU_usage_Equal_to( _lhs, _rhs ) \
> + #define CPU_usage_Equal_to( _lhs, _rhs ) \
> equal_to_uint32_t( _lhs, _rhs )
> #endif
>
> #ifndef __RTEMS_USE_TICKS_FOR_STATISTICS__
> -#define _Thread_CPU_usage_Set_to_zero( _time ) \
> + #define CPU_usage_Set_to_zero( _time ) \
> _Timestamp_Set_to_zero( _time )
> #else
> -#define _Thread_CPU_usage_Set_to_zero( _time ) \
> + #define CPU_usage_Set_to_zero( _time ) \
> do { \
> *_time = 0; \
> } while (0)
> #endif
>
> #ifndef __RTEMS_USE_TICKS_FOR_STATISTICS__
> -#define _Thread_CPU_usage_Less_than( _lhs, _rhs ) \
> + #define CPU_usage_Less_than( _lhs, _rhs ) \
> _Timestamp_Less_than( _lhs, _rhs )
> #else
> -#define _Thread_CPU_usage_Less_than( _lhs, _rhs ) \
> + #define CPU_usage_Less_than( _lhs, _rhs ) \
> less_than_uint32_t( _lhs, _rhs )
> #endif
>
> +static void
> +print_memsize(rtems_cpu_usage_data* data, const uint32_t size, const char* label)
> +{
> + if (size > (1024 * 1024))
> + (*data->plugin.print)(data->plugin.context, "%4" PRIu32 "M %s",
> + size / (1024 * 1024), label);
> + else if (size > 1024)
> + (*data->plugin.print)(data->plugin.context, "%4" PRIu32 "K %s",
> + size / 1024, label);
> + else
> + (*data->plugin.print)(data->plugin.context, "%4" PRIu32 " %s",
> + size, label);
> +}
> +
> +static int
> +print_time(rtems_cpu_usage_data* data,
> + const Timestamp_Control* time,
> + const int length)
> +{
> + uint32_t secs = _Timestamp_Get_seconds( time );
> + uint32_t usecs = _Timestamp_Get_nanoseconds( time ) / TOD_NANOSECONDS_PER_MICROSECOND;
> + int len = 0;
> +
> + if (secs > 60)
> + {
> + uint32_t mins = secs / 60;
> + if (mins > 60)
> + {
> + uint32_t hours = mins / 60;
> + if (hours > 24)
> + {
> + len += (*data->plugin.print)(data->plugin.context, "%" PRIu32 "d", hours / 24);
> + hours %= 24;
> + }
> + len += (*data->plugin.print)(data->plugin.context, "%" PRIu32 "hr", hours);
> + mins %= 60;
> + }
> + len += (*data->plugin.print)(data->plugin.context, "%" PRIu32 "m", mins);
> + secs %= 60;
> + }
> + len += (*data->plugin.print)(data->plugin.context, "%" PRIu32 ".%06" PRIu32, secs, usecs);
> +
> + if (len < length)
> + (*data->plugin.print)(data->plugin.context, "%*c", length - len, ' ');
> +
> + return len;
> +}
> +
> +/*
> + * Count the number of tasks.
> + */
> +static void
> +task_counter(Thread_Control *thrad, void* arg)
> +{
> + rtems_cpu_usage_data* data = (rtems_cpu_usage_data*) arg;
> + ++data->task_count;
> +}
> +
> +/*
> + * Create the usage and currant usage table for display.
> + */
> +static void
> +task_usage(Thread_Control* thread, void* arg)
> +{
> + rtems_cpu_usage_data* data = (rtems_cpu_usage_data*) arg;
> + Thread_CPU_usage_t usage = thread->cpu_time_used;
> + Thread_CPU_usage_t current = data->zero;
> + int j;
> +
> + data->stack_size += thread->Start.Initial_stack.size;
> +
> + for (j = 0; j < data->last_task_count; j++)
> + {
> + if (thread == data->last_tasks[j])
> + {
> + _Timestamp_Subtract(&data->last_usage[j], &usage, ¤t);
> + break;
> + }
> + }
> +
> + /*
> + * 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 guideline as
> + * to what each number means proportionally.
> + */
> + _Timestamp_Add_to(&data->total, &usage);
> + _Timestamp_Add_to(&data->current, ¤t);
> +
> + if (thread->Object.id == 0x09010001)
> + {
> + data->idle = usage;
> + data->current_idle = current;
> + }
> +
> + /*
> + * Create the tasks to display soring as we create.
> + */
> + for (j = 0; j < data->task_count; j++)
> + {
> + if (data->tasks[j])
> + {
> + int k;
> +
> + /*
> + * Sort on the current load.
> + */
> + if (data->sort_current)
> + {
> + if (CPU_usage_Equal_to(¤t, &data->zero) ||
> + CPU_usage_Less_than(¤t, &data->current_usage[j]))
> + continue;
> + }
> + else
> + {
> + if (CPU_usage_Equal_to(&usage, &data->zero) ||
> + CPU_usage_Less_than(&usage, &data->usage[j]))
> + continue;
> + }
> + for (k = (data->task_count - 1); k >= j; k--)
> + {
> + data->tasks[k + 1] = data->tasks[k];
> + data->usage[k + 1] = data->usage[k];
> + data->current_usage[k + 1] = data->current_usage[k];
> + }
> + }
> + data->tasks[j] = thread;
> + data->usage[j] = usage;
> + data->current_usage[j] = current;
> + break;
> + }
> +}
> +
> /*
> * rtems_cpuusage_top_thread
> *
> @@ -94,202 +295,251 @@ static inline bool less_than_uint32_t( uint32_t * lhs, uint32_t * rhs )
> static void
> rtems_cpuusage_top_thread (rtems_task_argument arg)
> {
> - uint32_t api_index;
> - Thread_Control* the_thread;
> - int i;
> - int j;
> - int k;
> - Objects_Information* information;
> - char name[13];
> - int task_count = 0;
> - uint32_t seconds, nanoseconds;
> - rtems_cpu_usage_plugin_t* plugin = (rtems_cpu_usage_plugin_t*)arg;
> - Thread_Control* load_tasks[RTEMS_CPUUSAGE_TOP_MAX_LOAD_TASKS + 1];
> - Thread_CPU_usage_t load[RTEMS_CPUUSAGE_TOP_MAX_LOAD_TASKS + 1];
> - Thread_CPU_usage_t zero;
> - Timestamp_Control uptime;
> - uint32_t ival, fval;
> -
> - while (true) {
> - #ifndef __RTEMS_USE_TICKS_FOR_STATISTICS__
> - Timestamp_Control total, ran, uptime_at_last_reset;
> - #else
> - uint32_t total_units = 0;
> - #endif
> + rtems_cpu_usage_data* data = (rtems_cpu_usage_data*) arg;
> + char name[13];
> + int i;
> + Heap_Information_block wksp;
> + uint32_t ival, fval;
> + int task_count;
> + rtems_event_set out;
> + rtems_status_code sc;
> + bool first_time = true;
>
> - rtems_cpuusage_top_thread_active = 1;
> + data->thread_active = true;
>
> - _Thread_CPU_usage_Set_to_zero( &zero);
> - memset (load_tasks, 0, sizeof (load_tasks));
> - for (i=0; i< (RTEMS_CPUUSAGE_TOP_MAX_LOAD_TASKS + 1); i++)
> - _Thread_CPU_usage_Set_to_zero( &load[i] );
> + _TOD_Get_uptime(&data->last_uptime);
>
> - /*
> - * Iterate over the tasks and sort the highest load tasks
> - * into our local arrays. We only handle a limited number of
> - * tasks.
> - */
> - for ( api_index = 1 ; api_index <= OBJECTS_APIS_LAST ; api_index++ ) {
> - #if !defined(RTEMS_POSIX_API) || defined(RTEMS_DEBUG)
> - if ( !_Objects_Information_table[ api_index ] )
> - continue;
> - #endif
> -
> - information = _Objects_Information_table[ api_index ][ 1 ];
> - if ( information ) {
> - for ( i=1 ; i <= information->maximum ; i++ ) {
> - the_thread = (Thread_Control *)information->local_table[ i ];
> - if ( the_thread ) {
> - Thread_CPU_usage_t usage = the_thread->cpu_time_used;
> -
> - /*
> - * 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
> - * guideline as to what each number means proportionally.
> - */
> - #ifdef __RTEMS_USE_TICKS_FOR_STATISTICS__
> - total_units += usage;
> - #endif
> -
> - /* Count the number of tasks and sort this load value */
> - task_count++;
> - for (j = 0; j < RTEMS_CPUUSAGE_TOP_MAX_LOAD_TASKS; j++) {
> - if (load_tasks[j]) {
> - if ( _Thread_CPU_usage_Equal_to( &usage, &zero) ||
> - _Thread_CPU_usage_Less_than( &usage, &load[j]))
> - continue;
> - for (k = (RTEMS_CPUUSAGE_TOP_MAX_LOAD_TASKS - 1); k >= j; k--){
> - load_tasks[k + 1] = load_tasks[k];
> - load[k + 1] = load[k];
> - }
> - }
> - load_tasks[j] = the_thread;
> - load[j] = usage;
> - break;
> - }
> - }
> - }
> + CPU_usage_Set_to_zero(&data->zero);
> +
> + while (data->thread_run)
> + {
> + Timestamp_Control uptime_at_last_reset = CPU_usage_Uptime_at_last_reset;
> + size_t tasks_size;
> + size_t usage_size;
> + Timestamp_Control load;
> +
> + data->task_count = 0;
> + rtems_iterate_over_all_threads_2(task_counter, data);
> +
> + tasks_size = sizeof(Thread_Control*) * (data->task_count + 1);
> + usage_size = sizeof(Thread_CPU_usage_t) * (data->task_count + 1);
> +
> + if (data->task_count > data->task_size)
> + {
> + data->tasks = realloc(data->tasks, tasks_size);
> + data->usage = realloc(data->usage, usage_size);
> + data->current_usage = realloc(data->current_usage, usage_size);
> + if ((data->tasks == NULL) || (data->usage == NULL) || (data->current_usage == NULL))
> + {
> + (*data->plugin.print)(data->plugin.context, "top worker: error: no memory\n");
> + data->thread_run = false;
> + break;
> }
> }
>
> - #ifndef __RTEMS_USE_TICKS_FOR_STATISTICS__
> - _Timestamp_Set_to_zero( &total );
> - uptime_at_last_reset = CPU_usage_Uptime_at_last_reset;
> - #endif
> + memset(data->tasks, 0, tasks_size);
> + memset(data->usage, 0, usage_size);
> + memset(data->current_usage, 0, usage_size);
>
> - _TOD_Get_uptime( &uptime );
> - seconds = _Timestamp_Get_seconds( &uptime );
> - nanoseconds = _Timestamp_Get_nanoseconds( &uptime ) /
> - TOD_NANOSECONDS_PER_MICROSECOND;
> - (*plugin->print)(plugin->context, "\x1b[H\x1b[J Press ENTER to exit.\n\n");
> - (*plugin->print)(plugin->context, "uptime: ");
> - (*plugin->print)(plugin->context,
> - "%7" PRIu32 ".%06" PRIu32 "\n", seconds, nanoseconds
> - );
> + _Timestamp_Set_to_zero(&data->total);
> + _Timestamp_Set_to_zero(&data->current);
> + data->stack_size = 0;
> +
> + _TOD_Get_uptime(&data->uptime);
> + _Timestamp_Subtract(&uptime_at_last_reset, &data->uptime, &data->uptime);
> + _Timestamp_Subtract(&data->last_uptime, &data->uptime, &data->period);
> + data->last_uptime = data->uptime;
>
> - (*plugin->print)(
> - plugin->context,
> - "-------------------------------------------------------------------------------\n"
> - " CPU USAGE BY THREAD\n"
> - "------------+---------------------+---------------+---------------+------------\n"
> - #ifndef __RTEMS_USE_TICKS_FOR_STATISTICS__
> - " ID | NAME | RPRI | CPRI | SECONDS | PERCENT\n"
> - #else
> - " ID | NAME | RPRI | CPRI | TICKS | PERCENT\n"
> - #endif
> - "------------+---------------------+---------------+---------------+------------\n"
> + rtems_iterate_over_all_threads_2(task_usage, data);
> +
> + if (data->task_count > data->task_size)
> + {
> + data->last_tasks = realloc(data->last_tasks, tasks_size);
> + data->last_usage = realloc(data->last_usage, usage_size);
> + if ((data->last_tasks == NULL) || (data->last_usage == NULL))
> + {
> + (*data->plugin.print)(data->plugin.context, "top worker: error: no memory\n");
> + data->thread_run = false;
> + break;
> + }
> + data->task_size = data->task_count;
> + }
> +
> + memcpy(data->last_tasks, data->tasks, tasks_size);
> + memcpy(data->last_usage, data->usage, usage_size);
> + data->last_task_count = data->task_count;
> +
> + if (data->sort_current && first_time)
> + {
> + rtems_task_wake_after(RTEMS_MILLISECONDS_TO_TICKS(500));
> + first_time = false;
> + continue;
> + }
> +
> + _Protected_heap_Get_information(&_Workspace_Area, &wksp);
> +
> + if (data->single_page)
> + (*data->plugin.print)(data->plugin.context,
> + "\x1b[H\x1b[J"
> + " <ENTER>:Exit <C>:%s <SPACE>:Refresh"
> + " <S>:Scroll <A>:All <+/->:Lines\n",
> + data->sort_current ? "Total " : "Current");
> + (*data->plugin.print)(data->plugin.context,"\n");
> +
> + /*
> + * Uptime and period of this sample.
> + */
> + (*data->plugin.print)(data->plugin.context, "Uptime: ");
> + print_time(data, &data->uptime, 20);
> + (*data->plugin.print)(data->plugin.context, " Period: ");
> + print_time(data, &data->period, 20);
> +
> + /*
> + * Task count, load and idle levels.
> + */
> + (*data->plugin.print)(data->plugin.context, "\nTasks: %4i ", data->task_count);
> +
> + _Timestamp_Subtract(&data->idle, &data->total, &load);
> + _Timestamp_Divide(&load, &data->uptime, &ival, &fval);
> + (*data->plugin.print)(data->plugin.context,
> + "Load Average: %4" PRIu32 ".%03" PRIu32 "%%", ival, fval);
> + _Timestamp_Subtract(&data->current_idle, &data->current, &load);
> + _Timestamp_Divide(&load, &data->period, &ival, &fval);
> + (*data->plugin.print)(data->plugin.context,
> + " Load: %4" PRIu32 ".%03" PRIu32 "%%", ival, fval);
> + _Timestamp_Divide(&data->current_idle, &data->period, &ival, &fval);
> + (*data->plugin.print)(data->plugin.context,
> + " Idle: %4" PRIu32 ".%03" PRIu32 "%%", ival, fval);
> +
> + /*
> + * Memory usage.
> + */
> + if (rtems_configuration_get_unified_work_area())
> + {
> + (*data->plugin.print)(data->plugin.context, "\nMem: ");
> + print_memsize(data, wksp.Free.total, "free");
> + print_memsize(data, wksp.Used.total, "used");
> + }
> + else
> + {
> + region_information_block libc_heap;
> + malloc_info(&libc_heap);
> + (*data->plugin.print)(data->plugin.context, "\nMem: Wksp: ");
> + print_memsize(data, wksp.Free.total, "free");
> + print_memsize(data, wksp.Used.total, "used Heap: ");
> + print_memsize(data, libc_heap.Free.total, "free");
> + print_memsize(data, libc_heap.Used.total, "used");
> + }
> +
> + print_memsize(data, data->stack_size, "stack\n");
> +
> + (*data->plugin.print)(data->plugin.context,
> + "\n"
> + " ID | NAME | RPRI | CPRI | TIME | TOTAL | CURRENT\n"
> + "------------+---------------------+---------------+---------------------+-----%s-+-----%s-\n",
> + data->sort_current ? "---" : "***",
> + data->sort_current ? "***" : "---"
> );
>
> - for (i = 0; i < RTEMS_CPUUSAGE_TOP_MAX_LOAD_TASKS; i++) {
> + task_count = 0;
> +
> + for (i = 0; i < data->task_count; i++)
> + {
> + Thread_Control* thread = data->tasks[i];
> + Timestamp_Control last;
> + Timestamp_Control usage;
> + Timestamp_Control current_usage;
>
> - if (!load_tasks[i])
> + if (thread == NULL)
> + break;
> +
> + if (data->single_page && (data->show != 0) && (i >= data->show))
> break;
>
> /*
> - * If this is the currently executing thread, account for time
> - * since the last context switch.
> + * We need to count the number displayed to clear the remainder of the
> + * the display.
> */
> - the_thread = load_tasks[i];
> -
> - rtems_object_get_name( the_thread->Object.id, sizeof(name), name );
> - (*plugin->print)(
> - plugin->context,
> - " 0x%08" PRIx32 " | %-19s | %3" PRId32 " | %3" PRId32 " |",
> - the_thread->Object.id,
> - name,
> - the_thread->real_priority,
> - the_thread->current_priority
> - );
> -
> - #ifndef __RTEMS_USE_TICKS_FOR_STATISTICS__
> - {
> - Timestamp_Control last;
> + ++task_count;
>
> - /*
> - * If this is the currently executing thread, account for time
> - * since the last context switch.
> - */
> - ran = load[i];
> - if ( _Thread_Get_time_of_last_context_switch( the_thread, &last ) ) {
> - Timestamp_Control used;
> - _TOD_Get_uptime( &uptime );
> - _Timestamp_Subtract( &last, &uptime, &used );
> - _Timestamp_Add_to( &ran, &used );
> - } else {
> - _TOD_Get_uptime( &uptime );
> - }
> - _Timestamp_Subtract( &uptime_at_last_reset, &uptime, &total );
> - _Timestamp_Divide( &ran, &total, &ival, &fval );
> + /*
> + * If the API os POSIX print the entry point.
> + */
> + rtems_object_get_name(thread->Object.id, sizeof(name), name);
> + if (name[0] == '\0')
> + snprintf(name, sizeof(name) - 1, "(%p)", thread->Start.entry_point);
> +
> + (*data->plugin.print)(data->plugin.context,
> + " 0x%08" PRIx32 " | %-19s | %3" PRId32 " | %3" PRId32 " | ",
> + thread->Object.id,
> + name,
> + thread->real_priority,
> + thread->current_priority);
> +
> + usage = data->usage[i];
> + current_usage = data->current_usage[i];
> +
> + /*
> + * If this is the currently executing thread, account for time since
> + * the last context switch.
> + */
> + if (_Thread_Get_time_of_last_context_switch(thread, &last))
> + {
> + Timestamp_Control used;
> + Timestamp_Control now;
>
> /*
> - * Print the information
> + * Get the current uptime and assume we are not pre-empted to
> + * measure the time from the last switch this thread and now.
> */
> -
> - seconds = _Timestamp_Get_seconds( &ran );
> - nanoseconds = _Timestamp_Get_nanoseconds( &ran ) /
> - TOD_NANOSECONDS_PER_MICROSECOND;
> - (*plugin->print)( plugin->context,
> - "%7" PRIu32 ".%06" PRIu32 " |%4" PRIu32 ".%03" PRIu32 "\n",
> - seconds, nanoseconds,
> - ival, fval
> - );
> + _TOD_Get_uptime(&now);
> + _Timestamp_Subtract(&last, &now, &used);
> + _Timestamp_Add_to(&usage, &used);
> + _Timestamp_Add_to(¤t_usage, &used);
> }
> - #else
> - if (total_units) {
> - uint64_t ival_64;
> -
> - ival_64 = load[i];
> - ival_64 *= 100000;
> - ival = ival_64 / total_units;
> - } else {
> - ival = 0;
> - }
> -
> - fval = ival % 1000;
> - ival /= 1000;
> - (*plugin->print)( plugin->context,
> - "%14" PRIu32 " |%4" PRIu32 ".%03" PRIu32 "\n",
> - load[i],
> - ival,
> - fval
> - );
> - #endif
> +
> + /*
> + * Print the information
> + */
> + print_time(data, &usage, 19);
> + _Timestamp_Divide(&usage, &data->total, &ival, &fval);
> + (*data->plugin.print)(data->plugin.context,
> + " |%4" PRIu32 ".%03" PRIu32, ival, fval);
> + _Timestamp_Divide(¤t_usage, &data->period, &ival, &fval);
> + (*data->plugin.print)(data->plugin.context,
> + " |%4" PRIu32 ".%03" PRIu32 "\n", ival, fval);
> }
>
> - if (task_count < RTEMS_CPUUSAGE_TOP_MAX_LOAD_TASKS)
> + if (data->single_page && (data->show != 0) && (task_count < data->show))
> {
> - j = RTEMS_CPUUSAGE_TOP_MAX_LOAD_TASKS - task_count;
> - while (j > 0)
> + i = data->show - task_count;
> + while (i > 0)
> {
> - (*plugin->print)( plugin->context, "\x1b[K\n");
> - j--;
> + (*data->plugin.print)(data->plugin.context, "\x1b[K\n");
> + i--;
> }
> }
>
> - rtems_cpuusage_top_thread_active = 0;
> -
> - rtems_task_wake_after (RTEMS_MICROSECONDS_TO_TICKS (5000000));
> + sc = rtems_event_receive(RTEMS_EVENT_1,
> + RTEMS_EVENT_ANY,
> + RTEMS_MILLISECONDS_TO_TICKS (data->poll_rate_usecs),
> + &out);
> + if ((sc != RTEMS_SUCCESSFUL) && (sc != RTEMS_TIMEOUT))
> + {
> + (*data->plugin.print)(data->plugin.context,
> + "error: event receive: %s\n", rtems_status_text(sc));
> + break;
> + }
> }
> +
> + free(data->tasks);
> + free(data->last_tasks);
> + free(data->last_usage);
> + free(data->current_usage);
> +
> + data->thread_active = false;
> +
> + rtems_task_delete (RTEMS_SELF);
> }
>
> void rtems_cpu_usage_top_with_plugin(
> @@ -297,17 +547,30 @@ void rtems_cpu_usage_top_with_plugin(
> rtems_printk_plugin_t print
> )
> {
> - rtems_status_code sc;
> - rtems_task_priority priority;
> - rtems_name name;
> - rtems_id id;
> - rtems_cpu_usage_plugin_t plugin;
> +#ifdef __RTEMS_USE_TICKS_FOR_STATISTICS__
> + if ( !print )
> + return;
> + (*print)(context, "error: tick kernels not supported\n");
> +#else
> + rtems_status_code sc;
> + rtems_task_priority priority;
> + rtems_name name;
> + rtems_id id;
> + rtems_cpu_usage_data data;
> + int show_lines = 25;
>
> if ( !print )
> return;
>
> - plugin.context = context;
> - plugin.print = print;
> + memset(&data, 0, sizeof(data));
> +
> + data.thread_run = true;
> + data.single_page = true;
> + data.sort_current = true;
> + data.poll_rate_usecs = 3000;
> + data.show = show_lines;
> + data.plugin.context = context;
> + data.plugin.print = print;
>
> sc = rtems_task_set_priority (RTEMS_SELF, RTEMS_CURRENT_PRIORITY, &priority);
>
> @@ -339,7 +602,7 @@ void rtems_cpu_usage_top_with_plugin(
> }
>
> sc = rtems_task_start (
> - id, rtems_cpuusage_top_thread, (rtems_task_argument)&plugin
> + id, rtems_cpuusage_top_thread, (rtems_task_argument) &data
> );
> if (sc != RTEMS_SUCCESSFUL)
> {
> @@ -352,23 +615,61 @@ void rtems_cpu_usage_top_with_plugin(
> return;
> }
>
> - for (;;)
> + while (true)
> {
> int c = getchar ();
>
> - if ((c == '\r') || (c == '\n'))
> + if ((c == '\r') || (c == '\n') || (c == 'q') || (c == 'Q'))
> {
> - int loops = 20;
> + int loops = 50;
>
> - while (loops && rtems_cpuusage_top_thread_active)
> - rtems_task_wake_after (RTEMS_MICROSECONDS_TO_TICKS (100000));
> + data.thread_run = false;
> +
> + rtems_event_send(id, RTEMS_EVENT_1);
>
> - rtems_task_delete (id);
> + while (loops && data.thread_active)
> + rtems_task_wake_after (RTEMS_MICROSECONDS_TO_TICKS (100000));
>
> (*print)(context, "load monitoring stopped.\n");
> return;
> }
> + else if ((c == 'c') || (c == 'C'))
> + {
> + data.sort_current = !data.sort_current;
> + rtems_event_send(id, RTEMS_EVENT_1);
> + }
> + else if ((c == 's') || (c == 'S'))
> + {
> + data.single_page = !data.single_page;
> + rtems_event_send(id, RTEMS_EVENT_1);
> + }
> + else if ((c == 'a') || (c == 'A'))
> + {
> + if (data.show == 0)
> + data.show = show_lines;
> + else
> + data.show = 0;
> + rtems_event_send(id, RTEMS_EVENT_1);
> + }
> + else if (c == '+')
> + {
> + ++show_lines;
> + if (data.show != 0)
> + data.show = show_lines;
> + }
> + else if (c == '-')
> + {
> + if (show_lines > 5)
> + --show_lines;
> + if (data.show != 0)
> + data.show = show_lines;
> + }
> + else if (c == ' ')
> + {
> + rtems_event_send(id, RTEMS_EVENT_1);
> + }
> }
> +#endif
> }
>
> void rtems_cpu_usage_top( void )
> --
> 2.2.2
>
> _______________________________________________
> devel mailing list
> devel at rtems.org
> http://lists.rtems.org/mailman/listinfo/devel
More information about the devel
mailing list