summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--cpukit/libmisc/cpuuse/cpuusagetop.c736
1 files changed, 541 insertions, 195 deletions
diff --git a/cpukit/libmisc/cpuuse/cpuusagetop.c b/cpukit/libmisc/cpuuse/cpuusagetop.c
index e47ba592fd..e4a47fe6d3 100644
--- a/cpukit/libmisc/cpuuse/cpuusagetop.c
+++ b/cpukit/libmisc/cpuuse/cpuusagetop.c
@@ -6,6 +6,8 @@
*/
/*
+ * COPYRIGHT (c) 2015. Chris Johns <chrisj@rtems.org>
+ *
* COPYRIGHT (c) 2014.
* On-Line Applications Research Corporation (OAR).
*
@@ -14,10 +16,15 @@
* http://www.rtems.org/license/LICENSE.
*/
+/*
+ * Based on the old capture engine ct-load.
+ */
+
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
+#include <stdbool.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
@@ -25,29 +32,107 @@
#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;
-#define RTEMS_CPUUSAGE_TOP_MAX_LOAD_TASKS (20)
+/*
+ * 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 uint32_t sort_order;
+ 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;
+/*
+ * Sort orders.
+ */
+#define RTEMS_TOP_SORT_ID (0)
+#define RTEMS_TOP_SORT_REAL_PRI (1)
+#define RTEMS_TOP_SORT_CURRENT_PRI (2)
+#define RTEMS_TOP_SORT_TOTAL (3)
+#define RTEMS_TOP_SORT_CURRENT (4)
+#define RTEMS_TOP_SORT_MAX (4)
+
+/*
+ * Private version of the iterator with an arg. This will be moved
+ * to the public version in 5.0.
+ */
+
+typedef void (*rtems_per_thread_routine_2)( Thread_Control *, void* );
+
+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 +145,175 @@ 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 sorted table with the current and total usage.
+ */
+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, &current);
+ 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, &current);
+
+ 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.
+ */
+ switch (data->sort_order)
+ {
+ default:
+ data->sort_order = RTEMS_TOP_SORT_CURRENT;
+ /* drop through */
+ case RTEMS_TOP_SORT_CURRENT:
+ if (CPU_usage_Equal_to(&current, &data->zero) ||
+ CPU_usage_Less_than(&current, &data->current_usage[j]))
+ continue;
+ case RTEMS_TOP_SORT_TOTAL:
+ if (CPU_usage_Equal_to(&usage, &data->zero) ||
+ CPU_usage_Less_than(&usage, &data->usage[j]))
+ continue;
+ case RTEMS_TOP_SORT_REAL_PRI:
+ if (thread->real_priority > data->tasks[j]->real_priority)
+ continue;
+ case RTEMS_TOP_SORT_CURRENT_PRI:
+ if (thread->current_priority > data->tasks[j]->current_priority)
+ continue;
+ case RTEMS_TOP_SORT_ID:
+ if (thread->Object.id < data->tasks[j]->Object.id)
+ 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 +323,257 @@ 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;
+
+ 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;
+
+ /*
+ * We need to loop again to get suitable current usage values as we need a
+ * last sample to work.
+ */
+ if (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 SPACE:Refresh"
+ " S:Scroll A:All <>:Order +/-:Lines\n");
+ (*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");
+ }
- (*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"
+ 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-----%s-----+---------------------+-%s------+--%s----\n",
+ data->sort_order == RTEMS_TOP_SORT_ID ? "^^" : "--",
+ data->sort_order == RTEMS_TOP_SORT_REAL_PRI ? "^^" : "--",
+ data->sort_order == RTEMS_TOP_SORT_CURRENT_PRI ? "^^" : "--",
+ data->sort_order == RTEMS_TOP_SORT_TOTAL ? "^^" : "--",
+ data->sort_order == RTEMS_TOP_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 (thread == NULL)
+ break;
- if (!load_tasks[i])
+ 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(&current_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(&current_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 +581,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_order = RTEMS_TOP_SORT_CURRENT;
+ 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 +636,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 +649,72 @@ 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_task_delete (id);
+ rtems_event_send(id, RTEMS_EVENT_1);
+
+ while (loops && data.thread_active)
+ rtems_task_wake_after (RTEMS_MICROSECONDS_TO_TICKS (100000));
(*print)(context, "load monitoring stopped.\n");
return;
}
+ else if (c == '<')
+ {
+ if (data.sort_order == 0)
+ data.sort_order = RTEMS_TOP_SORT_MAX;
+ else
+ --data.sort_order;
+ rtems_event_send(id, RTEMS_EVENT_1);
+ }
+ else if (c == '>')
+ {
+ if (data.sort_order >= RTEMS_TOP_SORT_MAX)
+ data.sort_order = 0;
+ else
+ ++data.sort_order;
+ 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 )