[PATCH 6/9] libmisc: Add top to cpuusage.

Jennifer Averett jennifer.averett at oarcorp.com
Tue Sep 30 14:13:25 UTC 2014


---
 cpukit/libmisc/Makefile.am          |   2 +-
 cpukit/libmisc/cpuuse/cpuusagetop.c | 338 ++++++++++++++++++++++++++++++++++++
 cpukit/libmisc/cpuuse/cpuuse.h      |  19 ++
 3 files changed, 358 insertions(+), 1 deletion(-)
 create mode 100644 cpukit/libmisc/cpuuse/cpuusagetop.c

diff --git a/cpukit/libmisc/Makefile.am b/cpukit/libmisc/Makefile.am
index 820a838..6c13071 100644
--- a/cpukit/libmisc/Makefile.am
+++ b/cpukit/libmisc/Makefile.am
@@ -27,7 +27,7 @@ EXTRA_DIST += cpuuse/README
 
 noinst_LIBRARIES += libcpuuse.a
 libcpuuse_a_SOURCES = cpuuse/cpuusagereport.c cpuuse/cpuusagereset.c \
-    cpuuse/cpuuse.h cpuuse/cpuusagedata.c
+     cpuuse/cpuuse.h cpuuse/cpuusagedata.c cpuuse/cpuusagetop.c
 
 ## devnull
 noinst_LIBRARIES += libdevnull.a
diff --git a/cpukit/libmisc/cpuuse/cpuusagetop.c b/cpukit/libmisc/cpuuse/cpuusagetop.c
new file mode 100644
index 0000000..6158917
--- /dev/null
+++ b/cpukit/libmisc/cpuuse/cpuusagetop.c
@@ -0,0 +1,338 @@
+/**
+ * @file
+ *
+ * @brief CPU Usage Top
+ * @ingroup libmisc_cpuuse CPU Usage
+ */
+
+/*
+ *  COPYRIGHT (c) 2014.
+ *  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.org/license/LICENSE.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <inttypes.h>
+
+#include <rtems/cpuuse.h>
+#include <rtems/score/objectimpl.h>
+#include <rtems/score/threadimpl.h>
+#include <rtems/score/todimpl.h>
+#include <rtems/score/watchdogimpl.h>
+
+
+/*
+ * Common variable to sync the load monitor task.
+ */
+static volatile int rtems_cpuusage_top_thread_active;
+
+
+typedef struct {
+  void                  *context;
+  rtems_printk_plugin_t  print;
+}rtems_cpu_usage_plugin_t;
+
+#define RTEMS_CPUUSAGE_TOP_MAX_LOAD_TASKS (20)
+
+/*
+ * rtems_cpuusage_top_thread
+ *
+ *  DESCRIPTION:
+ *
+ * This function displays the load of the tasks on an ANSI terminal.
+ *
+ */
+
+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];
+  unsigned long long        load[RTEMS_CPUUSAGE_TOP_MAX_LOAD_TASKS + 1];
+
+  while (true)
+  {
+    #ifndef __RTEMS_USE_TICKS_FOR_STATISTICS__
+      Timestamp_Control  uptime, total, ran, uptime_at_last_reset;
+    #else
+      uint32_t           total_units = 0;
+    #endif
+
+    rtems_cpuusage_top_thread_active = 1;
+
+    memset (load_tasks, 0, sizeof (load_tasks));
+    memset (load, 0, sizeof (load));
+
+   /*
+     * 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 ( k=1 ; k <= information->maximum ; k++ ) {
+          the_thread = (Thread_Control *)information->local_table[ k ];
+          if ( the_thread ) {
+
+            Thread_CPU_usage_t l = 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 += l;
+            #endif
+
+            /* Count the number of tasks and sort this load value */
+            task_count++;
+            for (i = 0; i < RTEMS_CPUUSAGE_TOP_MAX_LOAD_TASKS; i++) {
+              if (load_tasks[i]) {
+                if ((l == 0) || (l < load[i]))
+                  continue;
+                for (j = (RTEMS_CPUUSAGE_TOP_MAX_LOAD_TASKS - 1); j >= i; j--){
+                  load_tasks[j + 1] = load_tasks[j];
+                  load[j + 1]  = load[j];
+                }
+              }
+              load_tasks[i] = the_thread;
+              load[i]  = l;
+              break;
+            }
+          }
+        }
+      }
+    }
+
+    #ifndef __RTEMS_USE_TICKS_FOR_STATISTICS__
+      _Timestamp_Set_to_zero( &total );
+      uptime_at_last_reset = CPU_usage_Uptime_at_last_reset;
+    #endif
+
+    _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
+    );
+ 
+    (*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"
+    );
+
+    for (i = 0; i < RTEMS_CPUUSAGE_TOP_MAX_LOAD_TASKS; i++)
+    {
+ 
+      if (!load_tasks[i])
+        break;
+
+      /*
+       * If this is the currently executing thread, account for time
+       * since the last context switch.
+       */
+      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;
+        uint32_t          ival, fval;
+
+        /*
+         * 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 );
+
+        /*
+         * Print the information
+         */
+
+        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
+        );
+      }
+      #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
+    }
+
+    if (task_count < RTEMS_CPUUSAGE_TOP_MAX_LOAD_TASKS)
+    {
+      j = RTEMS_CPUUSAGE_TOP_MAX_LOAD_TASKS - task_count;
+      while (j > 0)
+      {
+       (*plugin->print)( plugin->context, "\x1b[K\n");
+        j--;
+      }
+    }
+
+    rtems_cpuusage_top_thread_active = 0;
+
+    rtems_task_wake_after (RTEMS_MICROSECONDS_TO_TICKS (5000000));
+  }
+}
+
+void rtems_cpu_usage_top_with_plugin(
+  void                  *context,
+  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;
+
+  if ( !print )
+    return;
+
+  plugin.context = context;
+  plugin.print   = print;
+
+  sc = rtems_task_set_priority (RTEMS_SELF, RTEMS_CURRENT_PRIORITY, &priority);
+
+  if (sc != RTEMS_SUCCESSFUL)
+  {
+    (*print)(
+       context,
+       "error: cannot obtain the current priority: %s\n",
+       rtems_status_text (sc)
+    );
+    return;
+  }
+
+  name = rtems_build_name('C', 'P', 'l', 't');
+
+  sc = rtems_task_create (name, priority, 4 * 1024,
+                          RTEMS_NO_FLOATING_POINT | RTEMS_LOCAL,
+                          RTEMS_PREEMPT | RTEMS_TIMESLICE | RTEMS_NO_ASR,
+                          &id);
+
+  if (sc != RTEMS_SUCCESSFUL)
+  {
+    (*print)(
+       context,
+       "error: cannot create helper thread: %s\n",
+       rtems_status_text (sc)
+    );
+    return;
+  }
+
+  sc = rtems_task_start (
+    id, rtems_cpuusage_top_thread, (rtems_task_argument)&plugin
+  );
+  if (sc != RTEMS_SUCCESSFUL)
+  {
+    (*print)(
+       context,
+       "error: cannot start helper thread: %s\n",
+       rtems_status_text (sc)
+    );
+    rtems_task_delete (id);
+    return;
+  }
+
+  for (;;)
+  {
+    int c = getchar ();
+
+    if ((c == '\r') || (c == '\n'))
+    {
+      int loops = 20;
+
+      while (loops && rtems_cpuusage_top_thread_active)
+        rtems_task_wake_after (RTEMS_MICROSECONDS_TO_TICKS (100000));
+
+      rtems_task_delete (id);
+
+      (*print)(context, "load monitoring stopped.\n");
+      return;
+    }
+  }
+}
+
+void rtems_cpu_usage_top( void )
+{
+  rtems_cpu_usage_top_with_plugin( NULL, printk_plugin );
+}
+
diff --git a/cpukit/libmisc/cpuuse/cpuuse.h b/cpukit/libmisc/cpuuse/cpuuse.h
index 1aee275..6426dcf 100644
--- a/cpukit/libmisc/cpuuse/cpuuse.h
+++ b/cpukit/libmisc/cpuuse/cpuuse.h
@@ -63,6 +63,25 @@ void rtems_cpu_usage_report_with_plugin(
 void rtems_cpu_usage_report( void );
 
 /**
+ *   @brief CPU usage Top plugin
+ *
+ *   Report CPU Usage in top format to 
+ *   to a print plugin.
+ */
+void rtems_cpu_usage_top_with_plugin(
+  void                  *context,
+  rtems_printk_plugin_t  print
+);
+
+/**
+ *  @brief CPU usage top.
+ *
+ *  CPU Usage top
+ */
+
+void rtems_cpu_usage_top( void );
+
+/**
  *  @brief Reset CPU usage.
  *
  *  CPU Usage Reporter
-- 
1.8.1.4



More information about the devel mailing list