forked from Imagelibrary/rtems
Methods to print the data were moved from capture-cli into a support area and are no longer static so that they can be shared by test routines, or application code that wants to use the capture engine without the shell interface.
1253 lines
30 KiB
C
1253 lines
30 KiB
C
/*
|
|
------------------------------------------------------------------------
|
|
|
|
Copyright Objective Design Systems Pty Ltd, 2002
|
|
All rights reserved Objective Design Systems Pty Ltd, 2002
|
|
Chris Johns (ccj@acm.org)
|
|
|
|
COPYRIGHT (c) 1989-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.
|
|
|
|
This software with is provided ``as is'' and with NO WARRANTY.
|
|
|
|
------------------------------------------------------------------------
|
|
|
|
RTEMS Performance Monitoring and Measurement Framework.
|
|
|
|
This is the Target Interface Command Line Interface. You need
|
|
start the RTEMS monitor.
|
|
|
|
*/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include "config.h"
|
|
#endif
|
|
|
|
#include <ctype.h>
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <inttypes.h>
|
|
|
|
#include <rtems.h>
|
|
#include <rtems/capture-cli.h>
|
|
#include <rtems/captureimpl.h>
|
|
#include <rtems/monitor.h>
|
|
#include <rtems/cpuuse.h>
|
|
#
|
|
#define RC_UNUSED __attribute__((unused))
|
|
|
|
#define RTEMS_CAPTURE_CLI_MAX_LOAD_TASKS (20)
|
|
|
|
/*
|
|
* Counter used to count the number of active tasks.
|
|
*/
|
|
static int rtems_capture_cli_task_count = 0;
|
|
|
|
/*
|
|
* The user capture timestamper.
|
|
*/
|
|
static rtems_capture_timestamp capture_timestamp;
|
|
|
|
/*
|
|
* rtems_capture_cli_open
|
|
*
|
|
* DESCRIPTION:
|
|
*
|
|
* This function opens the capture engine. We need the size of the
|
|
* capture buffer.
|
|
*
|
|
*/
|
|
|
|
static const char* open_usage = "usage: copen [-i] size\n";
|
|
|
|
static void
|
|
rtems_capture_cli_open (int argc,
|
|
char** argv,
|
|
const rtems_monitor_command_arg_t* command_arg RC_UNUSED,
|
|
bool verbose RC_UNUSED)
|
|
{
|
|
uint32_t size = 0;
|
|
bool enable = false;
|
|
rtems_status_code sc;
|
|
int arg;
|
|
|
|
if (argc <= 1)
|
|
{
|
|
fprintf (stdout, open_usage);
|
|
return;
|
|
}
|
|
|
|
for (arg = 1; arg < argc; arg++)
|
|
{
|
|
if (argv[arg][0] == '-')
|
|
{
|
|
if (argv[arg][1] == 'i')
|
|
enable = true;
|
|
else
|
|
fprintf (stdout, "warning: option -%c ignored\n", argv[arg][1]);
|
|
}
|
|
else
|
|
{
|
|
size = strtoul (argv[arg], 0, 0);
|
|
|
|
if (size < 100)
|
|
{
|
|
fprintf (stdout, "error: size must be greater than or equal to 100\n");
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
sc = rtems_capture_open (size, capture_timestamp);
|
|
|
|
if (sc != RTEMS_SUCCESSFUL)
|
|
{
|
|
fprintf (stdout, "error: open failed: %s\n", rtems_status_text (sc));
|
|
return;
|
|
}
|
|
|
|
fprintf (stdout, "capture engine opened.\n");
|
|
|
|
if (!enable)
|
|
return;
|
|
|
|
sc = rtems_capture_control (enable);
|
|
|
|
if (sc != RTEMS_SUCCESSFUL)
|
|
{
|
|
fprintf (stdout, "error: open enable failed: %s\n", rtems_status_text (sc));
|
|
return;
|
|
}
|
|
|
|
fprintf (stdout, "capture engine enabled.\n");
|
|
}
|
|
|
|
/*
|
|
* rtems_capture_cli_close
|
|
*
|
|
* DESCRIPTION:
|
|
*
|
|
* This function closes the capture engine.
|
|
*
|
|
*/
|
|
|
|
static void
|
|
rtems_capture_cli_close (int argc RC_UNUSED,
|
|
char** argv RC_UNUSED,
|
|
const rtems_monitor_command_arg_t* command_arg RC_UNUSED,
|
|
bool verbose RC_UNUSED)
|
|
{
|
|
rtems_status_code sc;
|
|
|
|
sc = rtems_capture_close ();
|
|
|
|
if (sc != RTEMS_SUCCESSFUL)
|
|
{
|
|
fprintf (stdout, "error: close failed: %s\n", rtems_status_text (sc));
|
|
return;
|
|
}
|
|
|
|
fprintf (stdout, "capture engine closed.\n");
|
|
}
|
|
|
|
/*
|
|
* rtems_capture_cli_enable
|
|
*
|
|
* DESCRIPTION:
|
|
*
|
|
* This function enables the capture engine.
|
|
*
|
|
*/
|
|
|
|
static void
|
|
rtems_capture_cli_enable (int argc RC_UNUSED,
|
|
char** argv RC_UNUSED,
|
|
const rtems_monitor_command_arg_t* command_arg RC_UNUSED,
|
|
bool verbose RC_UNUSED)
|
|
{
|
|
rtems_status_code sc;
|
|
|
|
sc = rtems_capture_control (1);
|
|
|
|
if (sc != RTEMS_SUCCESSFUL)
|
|
{
|
|
fprintf (stdout, "error: enable failed: %s\n", rtems_status_text (sc));
|
|
return;
|
|
}
|
|
|
|
fprintf (stdout, "capture engine enabled.\n");
|
|
}
|
|
|
|
/*
|
|
* rtems_capture_cli_disable
|
|
*
|
|
* DESCRIPTION:
|
|
*
|
|
* This function disables the capture engine.
|
|
*
|
|
*/
|
|
|
|
static void
|
|
rtems_capture_cli_disable (int argc RC_UNUSED,
|
|
char** argv RC_UNUSED,
|
|
const rtems_monitor_command_arg_t* command_arg RC_UNUSED,
|
|
bool verbose RC_UNUSED)
|
|
{
|
|
rtems_status_code sc;
|
|
|
|
sc = rtems_capture_control (0);
|
|
|
|
if (sc != RTEMS_SUCCESSFUL)
|
|
{
|
|
fprintf (stdout, "error: disable failed: %s\n", rtems_status_text (sc));
|
|
return;
|
|
}
|
|
|
|
fprintf (stdout, "capture engine disabled.\n");
|
|
}
|
|
|
|
static void
|
|
rtems_capture_cli_print_task (rtems_tcb *tcb)
|
|
{
|
|
rtems_task_priority ceiling = rtems_capture_watch_get_ceiling ();
|
|
rtems_task_priority floor = rtems_capture_watch_get_floor ();
|
|
rtems_task_priority priority;
|
|
int length;
|
|
|
|
priority = rtems_capture_task_real_priority (tcb);
|
|
|
|
fprintf (stdout, " ");
|
|
rtems_monitor_dump_id (rtems_capture_task_id (tcb));
|
|
fprintf (stdout, " ");
|
|
rtems_monitor_dump_name (rtems_capture_task_id (tcb));
|
|
fprintf (stdout, " ");
|
|
rtems_monitor_dump_priority (rtems_capture_task_start_priority (tcb));
|
|
fprintf (stdout, " ");
|
|
rtems_monitor_dump_priority (rtems_capture_task_real_priority (tcb));
|
|
fprintf (stdout, " ");
|
|
rtems_monitor_dump_priority (rtems_capture_task_curr_priority (tcb));
|
|
fprintf (stdout, " ");
|
|
length = rtems_monitor_dump_state (rtems_capture_task_state (tcb));
|
|
fprintf (stdout, "%*c", 14 - length, ' ');
|
|
fprintf (stdout, " %c%c",
|
|
'a',
|
|
rtems_capture_task_flags (tcb) & RTEMS_CAPTURE_TRACED ? 't' : '-');
|
|
|
|
if ((floor > ceiling) && (ceiling > priority))
|
|
fprintf (stdout, "--");
|
|
else
|
|
{
|
|
uint32_t flags = rtems_capture_task_control_flags (tcb);
|
|
fprintf (stdout, "%c%c",
|
|
rtems_capture_task_control (tcb) ?
|
|
(flags & RTEMS_CAPTURE_WATCH ? 'w' : '+') : '-',
|
|
rtems_capture_watch_global_on () ? 'g' : '-');
|
|
}
|
|
fprintf (stdout, "\n");
|
|
}
|
|
|
|
/*
|
|
* rtems_capture_cli_count_tasks
|
|
*
|
|
* DESCRIPTION:
|
|
*
|
|
* This function is called for each tcb and counts the
|
|
* number of tasks.
|
|
*
|
|
*/
|
|
|
|
static void
|
|
rtems_capture_cli_count_tasks (rtems_tcb *tcb)
|
|
{
|
|
rtems_capture_cli_task_count++;
|
|
}
|
|
|
|
|
|
/*
|
|
* rtems_capture_cli_task_list
|
|
*
|
|
* DESCRIPTION:
|
|
*
|
|
* This function lists the tasks the capture engine knows about.
|
|
*
|
|
*/
|
|
|
|
static void
|
|
rtems_capture_cli_task_list (int argc RC_UNUSED,
|
|
char** argv RC_UNUSED,
|
|
const rtems_monitor_command_arg_t* command_arg RC_UNUSED,
|
|
bool verbose RC_UNUSED)
|
|
{
|
|
rtems_capture_time_t uptime;
|
|
|
|
rtems_capture_time (&uptime);
|
|
|
|
rtems_capture_cli_task_count = 0;
|
|
rtems_iterate_over_all_threads (rtems_capture_cli_count_tasks);
|
|
|
|
fprintf (stdout, "uptime: ");
|
|
rtems_capture_print_timestamp (uptime);
|
|
fprintf (stdout, "\ntotal %i\n", rtems_capture_cli_task_count);
|
|
rtems_iterate_over_all_threads (rtems_capture_cli_print_task);
|
|
}
|
|
|
|
/*
|
|
* rtems_capture_cli_watch_list
|
|
*
|
|
* DESCRIPTION:
|
|
*
|
|
* This function lists the controls in the capture engine.
|
|
*
|
|
*/
|
|
|
|
static void
|
|
rtems_capture_cli_watch_list (int argc RC_UNUSED,
|
|
char** argv RC_UNUSED,
|
|
const rtems_monitor_command_arg_t* command_arg RC_UNUSED,
|
|
bool verbose RC_UNUSED)
|
|
{
|
|
rtems_capture_print_watch_list();
|
|
}
|
|
|
|
/*
|
|
* rtems_capture_cli_get_name_id
|
|
*
|
|
* DESCRIPTION:
|
|
*
|
|
* This function checks arguments for a name or an id.
|
|
*
|
|
*/
|
|
|
|
static bool
|
|
rtems_capture_cli_get_name_id (char* arg,
|
|
bool* valid_name,
|
|
bool* valid_id,
|
|
rtems_name* name,
|
|
rtems_id* id)
|
|
{
|
|
size_t l;
|
|
size_t i;
|
|
|
|
if (*valid_name && *valid_id)
|
|
{
|
|
fprintf (stdout, "error: too many arguments\n");
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* See if the arg is all hex digits.
|
|
*/
|
|
|
|
l = strlen (arg);
|
|
|
|
for (i = 0; i < l; i++)
|
|
if (!isxdigit ((unsigned char)arg[i]))
|
|
break;
|
|
|
|
if (i == l)
|
|
{
|
|
*id = strtoul (arg, 0, 16);
|
|
*valid_id = true;
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* This is a bit of hack but it should work on all platforms
|
|
* as it is what the score does with names.
|
|
*
|
|
* @warning The extra assigns play with the byte order so do not
|
|
* remove unless the score has been updated.
|
|
*/
|
|
rtems_name rname;
|
|
|
|
rname = rtems_build_name(arg[0], arg[1], arg[2], arg[3]);
|
|
*name = rname;
|
|
*valid_name = true;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
/*
|
|
* rtems_capture_cli_watch_add
|
|
*
|
|
* DESCRIPTION:
|
|
*
|
|
* This function is a monitor command that add a watch to the capture
|
|
* engine.
|
|
*
|
|
*/
|
|
|
|
static char const * watch_add_usage = "usage: cwadd [task name] [id]\n";
|
|
|
|
static void
|
|
rtems_capture_cli_watch_add (int argc,
|
|
char** argv,
|
|
const rtems_monitor_command_arg_t* command_arg RC_UNUSED,
|
|
bool verbose RC_UNUSED)
|
|
{
|
|
rtems_status_code sc;
|
|
int arg;
|
|
rtems_name name = 0;
|
|
rtems_id id = 0;
|
|
bool valid_name = false;
|
|
bool valid_id = false;
|
|
|
|
if (argc <= 1)
|
|
{
|
|
fprintf (stdout, watch_add_usage);
|
|
return;
|
|
}
|
|
|
|
for (arg = 1; arg < argc; arg++)
|
|
{
|
|
if (argv[arg][0] == '-')
|
|
{
|
|
fprintf (stdout, "warning: option -%c ignored\n", argv[arg][1]);
|
|
}
|
|
else
|
|
{
|
|
if (!rtems_capture_cli_get_name_id (argv[arg], &valid_name, &valid_id,
|
|
&name, &id))
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (!valid_name && !valid_id)
|
|
{
|
|
fprintf (stdout, "error: no valid name or task id located\n");
|
|
return;
|
|
}
|
|
|
|
sc = rtems_capture_watch_add (name, id);
|
|
|
|
if (sc != RTEMS_SUCCESSFUL)
|
|
{
|
|
fprintf (stdout,
|
|
"error: watch add failed: %s\n", rtems_status_text (sc));
|
|
return;
|
|
}
|
|
|
|
fprintf (stdout, "watch added.\n");
|
|
}
|
|
|
|
/*
|
|
* rtems_capture_cli_watch_del
|
|
*
|
|
* DESCRIPTION:
|
|
*
|
|
* This function is a monitor command that deletes a watch from the capture
|
|
* engine.
|
|
*
|
|
*/
|
|
|
|
static char const * watch_del_usage = "usage: cwdel [task name] [id]\n";
|
|
|
|
static void
|
|
rtems_capture_cli_watch_del (int argc,
|
|
char** argv,
|
|
const rtems_monitor_command_arg_t* command_arg RC_UNUSED,
|
|
bool verbose RC_UNUSED)
|
|
{
|
|
rtems_status_code sc;
|
|
int arg;
|
|
rtems_name name = 0;
|
|
rtems_id id = 0;
|
|
bool valid_name = false;
|
|
bool valid_id = false;
|
|
|
|
if (argc <= 1)
|
|
{
|
|
fprintf (stdout, watch_del_usage);
|
|
return;
|
|
}
|
|
|
|
for (arg = 1; arg < argc; arg++)
|
|
{
|
|
if (argv[arg][0] == '-')
|
|
{
|
|
fprintf (stdout, "warning: option -%c ignored\n", argv[arg][1]);
|
|
}
|
|
else
|
|
{
|
|
if (!rtems_capture_cli_get_name_id (argv[arg], &valid_name, &valid_id,
|
|
&name, &id))
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (!valid_name && !valid_id)
|
|
{
|
|
fprintf (stdout, "error: no valid name or task id located\n");
|
|
return;
|
|
}
|
|
|
|
sc = rtems_capture_watch_del (name, id);
|
|
|
|
if (sc != RTEMS_SUCCESSFUL)
|
|
{
|
|
fprintf (stdout, "error: watch delete failed: %s\n",
|
|
rtems_status_text (sc));
|
|
return;
|
|
}
|
|
|
|
fprintf (stdout, "watch delete.\n");
|
|
}
|
|
|
|
/*
|
|
* rtems_capture_cli_watch_control
|
|
*
|
|
* DESCRIPTION:
|
|
*
|
|
* This function is a monitor command that controls a watch.
|
|
*
|
|
*/
|
|
|
|
static char const * watch_control_usage = "usage: cwctl [task name] [id] on/off\n";
|
|
|
|
static void
|
|
rtems_capture_cli_watch_control (int argc,
|
|
char** argv,
|
|
const rtems_monitor_command_arg_t* command_arg RC_UNUSED,
|
|
bool verbose RC_UNUSED)
|
|
{
|
|
rtems_status_code sc;
|
|
int arg;
|
|
rtems_name name = 0;
|
|
rtems_id id = 0;
|
|
bool valid_name = false;
|
|
bool valid_id = false;
|
|
bool enable = false;
|
|
|
|
if (argc <= 2)
|
|
{
|
|
fprintf (stdout, watch_control_usage);
|
|
return;
|
|
}
|
|
|
|
for (arg = 1; arg < argc; arg++)
|
|
{
|
|
if (argv[arg][0] == '-')
|
|
{
|
|
fprintf (stdout, "warning: option -%c ignored\n", argv[arg][1]);
|
|
}
|
|
else
|
|
{
|
|
if (strcmp (argv[arg], "on") == 0)
|
|
enable = true;
|
|
else if (strcmp (argv[arg], "off") == 0)
|
|
enable = false;
|
|
else if (!rtems_capture_cli_get_name_id (argv[arg], &valid_name,
|
|
&valid_id, &name, &id))
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (!valid_name && !valid_id)
|
|
{
|
|
fprintf (stdout, "error: no valid name or task id located\n");
|
|
return;
|
|
}
|
|
|
|
sc = rtems_capture_watch_ctrl (name, id, enable);
|
|
|
|
if (sc != RTEMS_SUCCESSFUL)
|
|
{
|
|
fprintf (stdout, "error: watch control failed: %s\n",
|
|
rtems_status_text (sc));
|
|
return;
|
|
}
|
|
|
|
fprintf (stdout, "watch %s.\n", enable ? "enabled" : "disabled");
|
|
}
|
|
|
|
/*
|
|
* rtems_capture_cli_watch_global
|
|
*
|
|
* DESCRIPTION:
|
|
*
|
|
* This function is a monitor command that sets a global watch.
|
|
*
|
|
*/
|
|
|
|
static char const * watch_global_usage = "usage: cwglob on/off\n";
|
|
|
|
static void
|
|
rtems_capture_cli_watch_global (int argc,
|
|
char** argv,
|
|
const rtems_monitor_command_arg_t* command_arg RC_UNUSED,
|
|
bool verbose RC_UNUSED)
|
|
{
|
|
rtems_status_code sc;
|
|
int arg;
|
|
bool enable = false;
|
|
|
|
if (argc <= 1)
|
|
{
|
|
fprintf (stdout, watch_global_usage);
|
|
return;
|
|
}
|
|
|
|
for (arg = 1; arg < argc; arg++)
|
|
{
|
|
if (argv[arg][0] == '-')
|
|
{
|
|
fprintf (stdout, "warning: option -%c ignored\n", argv[arg][1]);
|
|
}
|
|
else
|
|
{
|
|
if (strcmp (argv[arg], "on") == 0)
|
|
enable = true;
|
|
else if (strcmp (argv[arg], "off") == 0)
|
|
enable = false;
|
|
}
|
|
}
|
|
|
|
sc = rtems_capture_watch_global (enable);
|
|
|
|
if (sc != RTEMS_SUCCESSFUL)
|
|
{
|
|
fprintf (stdout, "error: global watch failed: %s\n",
|
|
rtems_status_text (sc));
|
|
return;
|
|
}
|
|
|
|
fprintf (stdout, "global watch %s.\n", enable ? "enabled" : "disabled");
|
|
}
|
|
|
|
/*
|
|
* rtems_capture_cli_watch_ceiling
|
|
*
|
|
* DESCRIPTION:
|
|
*
|
|
* This function is a monitor command that sets watch ceiling.
|
|
*
|
|
*/
|
|
|
|
static char const * watch_ceiling_usage = "usage: cwceil priority\n";
|
|
|
|
static void
|
|
rtems_capture_cli_watch_ceiling (int argc,
|
|
char** argv,
|
|
const rtems_monitor_command_arg_t* command_arg RC_UNUSED,
|
|
bool verbose RC_UNUSED)
|
|
{
|
|
rtems_status_code sc;
|
|
int arg;
|
|
rtems_task_priority priority = 0;
|
|
|
|
if (argc <= 1)
|
|
{
|
|
fprintf (stdout, watch_ceiling_usage);
|
|
return;
|
|
}
|
|
|
|
for (arg = 1; arg < argc; arg++)
|
|
{
|
|
if (argv[arg][0] == '-')
|
|
{
|
|
fprintf (stdout, "warning: option -%c ignored\n", argv[arg][1]);
|
|
}
|
|
else
|
|
{
|
|
priority = strtoul (argv[arg], 0, 0);
|
|
}
|
|
}
|
|
|
|
sc = rtems_capture_watch_ceiling (priority);
|
|
|
|
if (sc != RTEMS_SUCCESSFUL)
|
|
{
|
|
fprintf (stdout, "error: watch ceiling failed: %s\n",
|
|
rtems_status_text (sc));
|
|
return;
|
|
}
|
|
|
|
fprintf (stdout, "watch ceiling is %" PRId32 ".\n", priority);
|
|
}
|
|
|
|
/*
|
|
* rtems_capture_cli_watch_floor
|
|
*
|
|
* DESCRIPTION:
|
|
*
|
|
* This function is a monitor command that sets watch floor.
|
|
*
|
|
*/
|
|
|
|
static char const * watch_floor_usage = "usage: cwfloor priority\n";
|
|
|
|
static void
|
|
rtems_capture_cli_watch_floor (int argc,
|
|
char** argv,
|
|
const rtems_monitor_command_arg_t* command_arg RC_UNUSED,
|
|
bool verbose RC_UNUSED)
|
|
{
|
|
rtems_status_code sc;
|
|
int arg;
|
|
rtems_task_priority priority = 0;
|
|
|
|
if (argc <= 1)
|
|
{
|
|
fprintf (stdout, watch_floor_usage);
|
|
return;
|
|
}
|
|
|
|
for (arg = 1; arg < argc; arg++)
|
|
{
|
|
if (argv[arg][0] == '-')
|
|
{
|
|
fprintf (stdout, "warning: option -%c ignored\n", argv[arg][1]);
|
|
}
|
|
else
|
|
{
|
|
priority = strtoul (argv[arg], 0, 0);
|
|
}
|
|
}
|
|
|
|
sc = rtems_capture_watch_floor (priority);
|
|
|
|
if (sc != RTEMS_SUCCESSFUL)
|
|
{
|
|
fprintf (stdout, "error: watch floor failed: %s\n",
|
|
rtems_status_text (sc));
|
|
return;
|
|
}
|
|
|
|
fprintf (stdout, "watch floor is %" PRId32 ".\n", priority);
|
|
}
|
|
|
|
/*
|
|
* rtems_capture_cli_trigger_worker
|
|
*
|
|
* DESCRIPTION:
|
|
*
|
|
* This function is a monitor command that sets or clears a trigger.
|
|
*
|
|
*/
|
|
|
|
static char const *trigger_set_usage =
|
|
"usage: %s [-?] type [to name/id] [from] [from name/id]\n";
|
|
|
|
static char const *trigger_set_types =
|
|
" You can say 'type TASK' or 'type TO from FROM'\n" \
|
|
" where TASK is the task the event is happening to\n" \
|
|
" or you can say the event TO this task FROM this task.\n" \
|
|
" No type defaults to 'switch'.\n" \
|
|
" switch : context switch TASK or FROM or FROM->TO\n" \
|
|
" create : create TASK, or create TO from FROM\n" \
|
|
" start : start TASK, or start TO from FROM\n" \
|
|
" restart : restart TASK, or restart TO from FROM\n" \
|
|
" delete : delete TASK or delete TO from FROM\n" \
|
|
" begin : begin TASK\n" \
|
|
" exitted : exitted TASK\n";
|
|
|
|
/*
|
|
* Structure to handle the parsing of the trigger command line.
|
|
*/
|
|
typedef struct rtems_capture_cli_triggers_s
|
|
{
|
|
char const * name;
|
|
rtems_capture_trigger_t type;
|
|
int to_only;
|
|
} rtems_capture_cli_triggers_t;
|
|
|
|
static rtems_capture_cli_triggers_t rtems_capture_cli_triggers[] =
|
|
{
|
|
{ "switch", rtems_capture_switch, 0 }, /* must be first */
|
|
{ "create", rtems_capture_create, 0 },
|
|
{ "start", rtems_capture_start, 0 },
|
|
{ "restart", rtems_capture_restart, 0 },
|
|
{ "delete", rtems_capture_delete, 0 },
|
|
{ "begin", rtems_capture_begin, 1 },
|
|
{ "exitted", rtems_capture_exitted, 1 }
|
|
};
|
|
|
|
typedef enum rtems_capture_cli_trig_state_e
|
|
{
|
|
trig_type,
|
|
trig_to,
|
|
trig_from_from,
|
|
trig_from
|
|
} rtems_capture_cli_trig_state_t;
|
|
|
|
#define RTEMS_CAPTURE_CLI_TRIGGERS_NUM \
|
|
(sizeof (rtems_capture_cli_triggers) / sizeof (rtems_capture_cli_triggers_t))
|
|
|
|
static void
|
|
rtems_capture_cli_trigger_worker (int set, int argc, char** argv)
|
|
{
|
|
rtems_status_code sc;
|
|
int arg;
|
|
int trigger = 0; /* switch */
|
|
rtems_capture_trigger_mode_t trigger_mode = rtems_capture_from_any;
|
|
bool trigger_set = false;
|
|
bool is_from = false;
|
|
bool is_to = false;
|
|
rtems_name name = 0;
|
|
rtems_id id = 0;
|
|
bool valid_name = false;
|
|
bool valid_id = false;
|
|
rtems_name from_name = 0;
|
|
rtems_id from_id = 0;
|
|
bool from_valid_name = false;
|
|
bool from_valid_id = false;
|
|
rtems_name to_name = 0;
|
|
rtems_id to_id = 0;
|
|
bool to_valid_name = false;
|
|
bool to_valid_id = false;
|
|
|
|
for (arg = 1; arg < argc; arg++)
|
|
{
|
|
if (argv[arg][0] == '-')
|
|
{
|
|
switch (argv[arg][1])
|
|
{
|
|
case '?':
|
|
fprintf (stdout, trigger_set_usage, set ? "ctset" : "ctclear");
|
|
fprintf (stdout, trigger_set_types);
|
|
return;
|
|
default:
|
|
fprintf (stdout, "warning: option -%c ignored\n", argv[arg][1]);
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (!trigger_set)
|
|
{
|
|
bool found = false;
|
|
int t;
|
|
|
|
for (t = 0; t < RTEMS_CAPTURE_CLI_TRIGGERS_NUM; t++)
|
|
if (strcmp (argv[arg], rtems_capture_cli_triggers[t].name) == 0)
|
|
{
|
|
trigger = t;
|
|
found = true;
|
|
break;
|
|
}
|
|
|
|
trigger_set = true;
|
|
|
|
/*
|
|
* If a trigger was not found assume the default and
|
|
* assume the parameter is a task name or id.
|
|
*/
|
|
if (found)
|
|
continue;
|
|
}
|
|
|
|
if (strcmp (arg[argv], "from") == 0)
|
|
{
|
|
if (from_valid_name || from_valid_id)
|
|
fprintf (stdout, "warning: extra 'from' ignored\n");
|
|
|
|
is_from = true;
|
|
continue;
|
|
}
|
|
|
|
if (strcmp (arg[argv], "to") == 0)
|
|
{
|
|
if (to_valid_name || from_valid_id)
|
|
fprintf (stdout, "warning: extra 'to' ignored\n");
|
|
|
|
is_to = true;
|
|
continue;
|
|
}
|
|
|
|
if (!rtems_capture_cli_get_name_id (argv[arg], &valid_name, &valid_id,
|
|
&name, &id))
|
|
return;
|
|
|
|
if (valid_name)
|
|
{
|
|
if (!is_from && !is_to)
|
|
is_to = true;
|
|
|
|
if (is_from)
|
|
{
|
|
if (!from_valid_name && !from_valid_id)
|
|
{
|
|
from_valid_name = true;
|
|
from_name = name;
|
|
}
|
|
else
|
|
fprintf (stdout, "warning: extra name arguments ignored\n");
|
|
}
|
|
else if (!to_valid_name && !to_valid_id)
|
|
{
|
|
to_valid_name = true;
|
|
to_name = name;
|
|
}
|
|
else
|
|
fprintf (stdout, "warning: extra name arguments ignored\n");
|
|
}
|
|
|
|
if (valid_id)
|
|
{
|
|
if (!is_from && !is_to)
|
|
is_to = true;
|
|
|
|
if (is_from)
|
|
{
|
|
if (!from_valid_name && !from_valid_id)
|
|
{
|
|
from_valid_id = true;
|
|
from_id = id;
|
|
}
|
|
else
|
|
fprintf (stdout, "warning: extra id arguments ignored\n");
|
|
}
|
|
else if (!to_valid_name && !to_valid_id)
|
|
{
|
|
to_valid_id = true;
|
|
to_id = id;
|
|
}
|
|
else
|
|
fprintf (stdout, "warning: extra id arguments ignored\n");
|
|
}
|
|
}
|
|
}
|
|
|
|
if (is_from && rtems_capture_cli_triggers[trigger].to_only)
|
|
{
|
|
fprintf (stdout, "error: a %s trigger can be a TO trigger\n",
|
|
rtems_capture_cli_triggers[trigger].name);
|
|
return;
|
|
}
|
|
|
|
if (!to_valid_name && !to_valid_id && !from_valid_name && !from_valid_id)
|
|
{
|
|
fprintf (stdout, trigger_set_usage, set ? "ctset" : "ctclear");
|
|
return;
|
|
}
|
|
|
|
if (!is_from && !to_valid_name && !to_valid_id)
|
|
{
|
|
fprintf (stdout, "error: a %s trigger needs a TO name or id\n",
|
|
rtems_capture_cli_triggers[trigger].name);
|
|
return;
|
|
}
|
|
|
|
if (is_from && !from_valid_name && !from_valid_id)
|
|
{
|
|
fprintf (stdout, "error: a %s trigger needs a FROM name or id\n",
|
|
rtems_capture_cli_triggers[trigger].name);
|
|
return;
|
|
}
|
|
|
|
if ((from_valid_name || from_valid_id) && (to_valid_name || to_valid_id))
|
|
trigger_mode = rtems_capture_from_to;
|
|
else if (from_valid_name || from_valid_id)
|
|
trigger_mode = rtems_capture_to_any;
|
|
else if (to_valid_name || to_valid_id)
|
|
trigger_mode = rtems_capture_from_any;
|
|
|
|
if (set)
|
|
sc = rtems_capture_set_trigger (from_name, from_id, to_name, to_id,
|
|
trigger_mode,
|
|
rtems_capture_cli_triggers[trigger].type);
|
|
else
|
|
sc = rtems_capture_clear_trigger (from_name, from_id, to_name, to_id,
|
|
trigger_mode,
|
|
rtems_capture_cli_triggers[trigger].type);
|
|
|
|
if (sc != RTEMS_SUCCESSFUL)
|
|
{
|
|
fprintf (stdout, "error: %sing the trigger failed: %s\n",
|
|
set ? "sett" : "clear", rtems_status_text (sc));
|
|
return;
|
|
}
|
|
|
|
fprintf (stdout, "trigger %s.\n", set ? "set" : "cleared");
|
|
}
|
|
|
|
/*
|
|
* rtems_capture_cli_trigger_set
|
|
*
|
|
* DESCRIPTION:
|
|
*
|
|
* This function is a monitor command that sets a trigger.
|
|
*
|
|
*/
|
|
|
|
static void
|
|
rtems_capture_cli_trigger_set (int argc,
|
|
char** argv,
|
|
const rtems_monitor_command_arg_t* command_arg RC_UNUSED,
|
|
bool verbose RC_UNUSED)
|
|
{
|
|
rtems_capture_cli_trigger_worker (1, argc, argv);
|
|
}
|
|
|
|
/*
|
|
* rtems_capture_cli_trigger_clear
|
|
*
|
|
* DESCRIPTION:
|
|
*
|
|
* This function is a monitor command that clears a trigger.
|
|
*
|
|
*/
|
|
|
|
static void
|
|
rtems_capture_cli_trigger_clear (int argc,
|
|
char** argv,
|
|
const rtems_monitor_command_arg_t* command_arg RC_UNUSED,
|
|
bool verbose RC_UNUSED)
|
|
{
|
|
rtems_capture_cli_trigger_worker (0, argc, argv);
|
|
}
|
|
|
|
/*
|
|
* rtems_capture_cli_trace_records
|
|
*
|
|
* DESCRIPTION:
|
|
*
|
|
* This function is a monitor command that dumps trace records.
|
|
*
|
|
*/
|
|
|
|
static void
|
|
rtems_capture_cli_trace_records (int argc,
|
|
char** argv,
|
|
const rtems_monitor_command_arg_t* command_arg RC_UNUSED,
|
|
bool verbose RC_UNUSED)
|
|
{
|
|
bool csv = false;
|
|
static int dump_total = 22;
|
|
int arg;
|
|
|
|
for (arg = 1; arg < argc; arg++)
|
|
{
|
|
if (argv[arg][0] == '-')
|
|
{
|
|
if (argv[arg][1] == 'c')
|
|
csv = true;
|
|
else
|
|
fprintf (stdout, "warning: option -%c ignored\n", argv[arg][1]);
|
|
}
|
|
else
|
|
{
|
|
size_t i;
|
|
size_t l;
|
|
|
|
l = strlen (argv[arg]);
|
|
|
|
for (i = 0; i < l; i++)
|
|
if (!isdigit ((unsigned char)argv[arg][i]))
|
|
{
|
|
fprintf (stdout, "error: not a number\n");
|
|
return;
|
|
}
|
|
|
|
dump_total = strtoul (argv[arg], 0, 0);
|
|
}
|
|
}
|
|
|
|
rtems_capture_print_trace_records( dump_total, csv );
|
|
}
|
|
|
|
/*
|
|
* rtems_capture_cli_flush
|
|
*
|
|
* DESCRIPTION:
|
|
*
|
|
* This function is a monitor command that flushes and primes the capture
|
|
* engine.
|
|
*
|
|
*/
|
|
|
|
static void
|
|
rtems_capture_cli_flush (int argc,
|
|
char** argv,
|
|
const rtems_monitor_command_arg_t* command_arg RC_UNUSED,
|
|
bool verbose RC_UNUSED)
|
|
{
|
|
rtems_status_code sc;
|
|
bool prime = true;
|
|
int arg;
|
|
|
|
for (arg = 1; arg < argc; arg++)
|
|
{
|
|
if (argv[arg][0] == '-')
|
|
{
|
|
if (argv[arg][1] == 'n')
|
|
prime = false;
|
|
else
|
|
fprintf (stdout, "warning: option -%c ignored\n", argv[arg][1]);
|
|
}
|
|
}
|
|
|
|
sc = rtems_capture_flush (prime);
|
|
|
|
if (sc != RTEMS_SUCCESSFUL)
|
|
{
|
|
fprintf (stdout, "error: flush failed: %s\n", rtems_status_text (sc));
|
|
return;
|
|
}
|
|
|
|
fprintf (stdout, "trace buffer flushed and %s.\n",
|
|
prime ? "primed" : "not primed");
|
|
}
|
|
|
|
static rtems_monitor_command_entry_t rtems_capture_cli_cmds[] =
|
|
{
|
|
{
|
|
"copen",
|
|
"usage: copen [-i] size\n",
|
|
0,
|
|
rtems_capture_cli_open,
|
|
{ 0 },
|
|
0
|
|
},
|
|
{
|
|
"cclose",
|
|
"usage: cclose\n",
|
|
0,
|
|
rtems_capture_cli_close,
|
|
{ 0 },
|
|
0
|
|
},
|
|
{
|
|
"cenable",
|
|
"usage: cenable\n",
|
|
0,
|
|
rtems_capture_cli_enable,
|
|
{ 0 },
|
|
0
|
|
},
|
|
{
|
|
"cdisable",
|
|
"usage: cdisable\n",
|
|
0,
|
|
rtems_capture_cli_disable,
|
|
{ 0 },
|
|
0
|
|
},
|
|
{
|
|
"ctlist",
|
|
"usage: ctlist \n",
|
|
0,
|
|
rtems_capture_cli_task_list,
|
|
{ 0 },
|
|
0
|
|
},
|
|
{
|
|
"cwlist",
|
|
"usage: cwlist\n",
|
|
0,
|
|
rtems_capture_cli_watch_list,
|
|
{ 0 },
|
|
0
|
|
},
|
|
{
|
|
"cwadd",
|
|
"usage: cwadd [task name] [id]\n",
|
|
0,
|
|
rtems_capture_cli_watch_add,
|
|
{ 0 },
|
|
0
|
|
},
|
|
{
|
|
"cwdel",
|
|
"usage: cwdel [task name] [id]\n",
|
|
0,
|
|
rtems_capture_cli_watch_del,
|
|
{ 0 },
|
|
0
|
|
},
|
|
{
|
|
"cwctl",
|
|
"usage: cwctl [task name] [id] on/off\n",
|
|
0,
|
|
rtems_capture_cli_watch_control,
|
|
{ 0 },
|
|
0
|
|
},
|
|
{
|
|
"cwglob",
|
|
"usage: cwglob on/off\n",
|
|
0,
|
|
rtems_capture_cli_watch_global,
|
|
{ 0 },
|
|
0
|
|
},
|
|
{
|
|
"cwceil",
|
|
"usage: cwceil priority\n",
|
|
0,
|
|
rtems_capture_cli_watch_ceiling,
|
|
{ 0 },
|
|
0
|
|
},
|
|
{
|
|
"cwfloor",
|
|
"usage: cwfloor priority\n",
|
|
0,
|
|
rtems_capture_cli_watch_floor,
|
|
{ 0 },
|
|
0
|
|
},
|
|
{
|
|
"ctrace",
|
|
"usage: ctrace [-c] [-r records]\n",
|
|
0,
|
|
rtems_capture_cli_trace_records,
|
|
{ 0 },
|
|
0
|
|
},
|
|
{
|
|
"ctset",
|
|
"usage: ctset -h\n",
|
|
0,
|
|
rtems_capture_cli_trigger_set,
|
|
{ 0 },
|
|
0
|
|
},
|
|
{
|
|
"ctclear",
|
|
"usage: ctclear -?\n",
|
|
0,
|
|
rtems_capture_cli_trigger_clear,
|
|
{ 0 },
|
|
0
|
|
},
|
|
{
|
|
"cflush",
|
|
"usage: cflush [-n]\n",
|
|
0,
|
|
rtems_capture_cli_flush,
|
|
{ 0 },
|
|
0
|
|
}
|
|
};
|
|
|
|
/*
|
|
* rtems_capture_cli_init
|
|
*
|
|
* DESCRIPTION:
|
|
*
|
|
* This function initialises the command line interface to the capture
|
|
* engine.
|
|
*
|
|
*/
|
|
|
|
rtems_status_code
|
|
rtems_capture_cli_init (rtems_capture_timestamp timestamp)
|
|
{
|
|
size_t cmd;
|
|
|
|
capture_timestamp = timestamp;
|
|
|
|
for (cmd = 0;
|
|
cmd < sizeof (rtems_capture_cli_cmds) / sizeof (rtems_monitor_command_entry_t);
|
|
cmd++)
|
|
rtems_monitor_insert_cmd (&rtems_capture_cli_cmds[cmd]);
|
|
|
|
return RTEMS_SUCCESSFUL;
|
|
}
|