diff options
author | Chris Johns <chrisj@rtems.org> | 2007-08-17 00:54:16 +0000 |
---|---|---|
committer | Chris Johns <chrisj@rtems.org> | 2007-08-17 00:54:16 +0000 |
commit | 1374fd3f072fbb87f0a7af5726fb8a2571a8688e (patch) | |
tree | 98a75d741a0c81388858f8ef645265b751270f59 /cpukit/libmisc/capture | |
parent | f41dd231655da361271b8a3d4a7fd5412e2f7088 (diff) |
2007-08-17 Chris Johns <chrisj@rtems.org>
* libmisc/capture/README: Minor copyright change.
* libmisc/capture/capture-cli.c, libmisc/capture/capture.c,
libmisc/capture/capture.h: Fixed the memory leak when lots of
tasks are being created and deleted. Improved the trigger
interface so all task type actions can be caught.
Diffstat (limited to 'cpukit/libmisc/capture')
-rw-r--r-- | cpukit/libmisc/capture/README | 2 | ||||
-rw-r--r-- | cpukit/libmisc/capture/capture-cli.c | 866 | ||||
-rw-r--r-- | cpukit/libmisc/capture/capture.c | 724 | ||||
-rw-r--r-- | cpukit/libmisc/capture/capture.h | 344 |
4 files changed, 1299 insertions, 637 deletions
diff --git a/cpukit/libmisc/capture/README b/cpukit/libmisc/capture/README index 2ea76a4cfe..d12b5570d6 100644 --- a/cpukit/libmisc/capture/README +++ b/cpukit/libmisc/capture/README @@ -4,7 +4,7 @@ RTEMS Performance Monitoring and Measurement Framework - Copyright 2002 Chris Johns (ccj@acm.org) + Copyright 2002-2007 Chris Johns (chrisj@rtems.org) 23 April 2002 This directory contains the source code for the performance monitoring and diff --git a/cpukit/libmisc/capture/capture-cli.c b/cpukit/libmisc/capture/capture-cli.c index 4c019a1958..42480df76b 100644 --- a/cpukit/libmisc/capture/capture-cli.c +++ b/cpukit/libmisc/capture/capture-cli.c @@ -38,7 +38,7 @@ #include <rtems/capture-cli.h> #include <rtems/monitor.h> -#define RTEMS_CAPTURE_CLI_MAX_LOAD_TASKS (32) +#define RTEMS_CAPTURE_CLI_MAX_LOAD_TASKS (20) /* * The user capture timestamper. @@ -63,20 +63,19 @@ static volatile int cli_load_thread_active; static const char* open_usage = "usage: copen [-i] size\n"; static void -rtems_capture_cli_open ( - int argc, - char **argv, - rtems_monitor_command_arg_t *command_arg, - boolean verbose ) +rtems_capture_cli_open (int argc, + char** argv, + rtems_monitor_command_arg_t* command_arg, + boolean verbose) { - uint32_t size = 0; + uint32_t size = 0; rtems_boolean enable = 0; rtems_status_code sc; int arg; if (argc <= 1) { - fprintf(stdout,open_usage); + fprintf (stdout, open_usage); return; } @@ -87,7 +86,7 @@ rtems_capture_cli_open ( if (argv[arg][1] == 'i') enable = 1; else - fprintf(stdout,"warning: option -%c ignored\n", argv[arg][1]); + fprintf (stdout, "warning: option -%c ignored\n", argv[arg][1]); } else { @@ -95,7 +94,7 @@ rtems_capture_cli_open ( if (size < 100) { - fprintf(stdout,"error: size must be greater than or equal to 100\n"); + fprintf (stdout, "error: size must be greater than or equal to 100\n"); return; } } @@ -105,11 +104,11 @@ rtems_capture_cli_open ( if (sc != RTEMS_SUCCESSFUL) { - fprintf(stdout,"error: open failed: %s\n", rtems_status_text (sc)); + fprintf (stdout, "error: open failed: %s\n", rtems_status_text (sc)); return; } - fprintf(stdout,"capture engine opened.\n"); + fprintf (stdout, "capture engine opened.\n"); if (!enable) return; @@ -118,11 +117,11 @@ rtems_capture_cli_open ( if (sc != RTEMS_SUCCESSFUL) { - fprintf(stdout,"error: open enable failed: %s\n", rtems_status_text (sc)); + fprintf (stdout, "error: open enable failed: %s\n", rtems_status_text (sc)); return; } - fprintf(stdout,"capture engine enabled.\n"); + fprintf (stdout, "capture engine enabled.\n"); } /* @@ -135,11 +134,10 @@ rtems_capture_cli_open ( */ static void -rtems_capture_cli_close ( - int argc, - char **argv, - rtems_monitor_command_arg_t *command_arg, - boolean verbose ) +rtems_capture_cli_close (int argc, + char** argv, + rtems_monitor_command_arg_t* command_arg, + boolean verbose) { rtems_status_code sc; @@ -147,11 +145,11 @@ rtems_capture_cli_close ( if (sc != RTEMS_SUCCESSFUL) { - fprintf(stdout,"error: close failed: %s\n", rtems_status_text (sc)); + fprintf (stdout, "error: close failed: %s\n", rtems_status_text (sc)); return; } - fprintf(stdout,"capture engine closed.\n"); + fprintf (stdout, "capture engine closed.\n"); } /* @@ -164,11 +162,10 @@ rtems_capture_cli_close ( */ static void -rtems_capture_cli_enable ( - int argc, - char **argv, - rtems_monitor_command_arg_t *command_arg, - boolean verbose ) +rtems_capture_cli_enable (int argc, + char** argv, + rtems_monitor_command_arg_t* command_arg, + boolean verbose) { rtems_status_code sc; @@ -176,11 +173,11 @@ rtems_capture_cli_enable ( if (sc != RTEMS_SUCCESSFUL) { - fprintf(stdout,"error: enable failed: %s\n", rtems_status_text (sc)); + fprintf (stdout, "error: enable failed: %s\n", rtems_status_text (sc)); return; } - fprintf(stdout,"capture engine enabled.\n"); + fprintf (stdout, "capture engine enabled.\n"); } /* @@ -193,11 +190,10 @@ rtems_capture_cli_enable ( */ static void -rtems_capture_cli_disable ( - int argc, - char **argv, - rtems_monitor_command_arg_t *command_arg, - boolean verbose ) +rtems_capture_cli_disable (int argc, + char** argv, + rtems_monitor_command_arg_t* command_arg, + boolean verbose) { rtems_status_code sc; @@ -205,11 +201,11 @@ rtems_capture_cli_disable ( if (sc != RTEMS_SUCCESSFUL) { - fprintf(stdout,"error: disable failed: %s\n", rtems_status_text (sc)); + fprintf (stdout, "error: disable failed: %s\n", rtems_status_text (sc)); return; } - fprintf(stdout,"capture engine disabled.\n"); + fprintf (stdout, "capture engine disabled.\n"); } /* @@ -222,17 +218,16 @@ rtems_capture_cli_disable ( */ static void -rtems_capture_cli_task_list ( - int argc, - char **argv, - rtems_monitor_command_arg_t *command_arg, - boolean verbose ) +rtems_capture_cli_task_list (int argc, + char** argv, + rtems_monitor_command_arg_t* command_arg, + boolean verbose) { rtems_task_priority ceiling = rtems_capture_watch_get_ceiling (); rtems_task_priority floor = rtems_capture_watch_get_floor (); rtems_capture_task_t* task = rtems_capture_get_task_list (); - uint32_t ticks; - uint32_t tick_offset; + uint32_t ticks; + uint32_t tick_offset; unsigned long long total_time; int count = rtems_capture_task_count (); @@ -244,9 +239,7 @@ rtems_capture_cli_task_list ( tick_offset = 0; } - total_time = (ticks * rtems_capture_task_time (task)) + tick_offset; - - fprintf(stdout,"total %i\n", count); + fprintf (stdout, "total %i\n", count); while (task) { @@ -254,12 +247,15 @@ rtems_capture_cli_task_list ( int32_t stack_used; int32_t time_used; - stack_used = rtems_capture_task_stack_usage (task) * 100; - stack_used /= rtems_capture_task_stack_size (task); + stack_used = rtems_capture_task_stack_usage (task); + if (stack_used) + stack_used = (stack_used * 100) / stack_used; if (stack_used > 100) stack_used = 100; + total_time = (ticks * rtems_capture_task_time (task)) + tick_offset; + time_used = (rtems_capture_task_time (task) * 100) / total_time; if (time_used > 100) @@ -267,32 +263,33 @@ rtems_capture_cli_task_list ( priority = rtems_capture_task_real_priority (task); - fprintf(stdout," "); + fprintf (stdout, " "); rtems_monitor_dump_id (rtems_capture_task_id (task)); - fprintf(stdout," "); + fprintf (stdout, " "); rtems_monitor_dump_name (rtems_capture_task_name (task)); - fprintf(stdout," "); + fprintf (stdout, " "); rtems_monitor_dump_priority (rtems_capture_task_start_priority (task)); - fprintf(stdout," "); + fprintf (stdout, " "); rtems_monitor_dump_priority (rtems_capture_task_real_priority (task)); - fprintf(stdout," "); + fprintf (stdout, " "); rtems_monitor_dump_priority (rtems_capture_task_curr_priority (task)); - fprintf(stdout," "); + fprintf (stdout, " "); rtems_monitor_dump_state (rtems_capture_task_state (task)); - fprintf(stdout," %c%c%c%c%c", - rtems_capture_task_valid (task) ? 'a' : 'd', - rtems_capture_task_flags (task) & RTEMS_CAPTURE_TRACED ? 't' : '-', - rtems_capture_task_control_flags (task) & RTEMS_CAPTURE_TO_ANY ? 'F' : '-', - rtems_capture_task_control_flags (task) & RTEMS_CAPTURE_FROM_ANY ? 'T' : '-', - rtems_capture_task_control_flags (task) & RTEMS_CAPTURE_FROM_TO ? 'E' : '-'); + fprintf (stdout, " %c%c", + rtems_capture_task_valid (task) ? 'a' : 'd', + rtems_capture_task_flags (task) & RTEMS_CAPTURE_TRACED ? 't' : '-'); + if ((floor > ceiling) && (ceiling > priority)) - fprintf(stdout,"--"); + fprintf (stdout, "--"); else - fprintf(stdout,"%c%c", - rtems_capture_task_control (task) ? - (rtems_capture_task_control_flags (task) & RTEMS_CAPTURE_WATCH ? 'w' : '+') : '-', - rtems_capture_watch_global_on () ? 'g' : '-'); - fprintf(stdout," %3" PRId32 "%% %3" PRId32 "%% (%" PRIu32 ")\n", + { + uint32_t flags = rtems_capture_task_control_flags (task); + fprintf (stdout, "%c%c", + rtems_capture_task_control (task) ? + (flags & RTEMS_CAPTURE_WATCH ? 'w' : '+') : '-', + rtems_capture_watch_global_on () ? 'g' : '-'); + } + fprintf (stdout, " %3" PRId32 "%% %3" PRId32 "%% (%" PRIu32 ")\n", stack_used, time_used, rtems_capture_task_ticks (task)); task = rtems_capture_next_task (task); @@ -314,10 +311,7 @@ rtems_capture_cli_task_load_thread (rtems_task_argument arg) rtems_task_priority ceiling = rtems_capture_watch_get_ceiling (); rtems_task_priority floor = rtems_capture_watch_get_floor (); int last_count = 0; - - fprintf(stdout,"\x1b[2J Press ENTER to exit.\n\n"); - fprintf(stdout," PID NAME RPRI CPRI STATE %%CPU %%STK FLGS EXEC TIME\n"); - + for (;;) { rtems_capture_task_t* tasks[RTEMS_CAPTURE_CLI_MAX_LOAD_TASKS + 1]; @@ -341,6 +335,8 @@ rtems_capture_cli_task_load_thread (rtems_task_argument arg) task = rtems_capture_get_task_list (); + total_time = 0; + while (task) { if (rtems_capture_task_valid (task)) @@ -349,6 +345,8 @@ rtems_capture_cli_task_load_thread (rtems_task_argument arg) count++; + total_time += l; + for (i = 0; i < RTEMS_CAPTURE_CLI_MAX_LOAD_TASKS; i++) { if (tasks[i]) @@ -371,12 +369,9 @@ rtems_capture_cli_task_load_thread (rtems_task_argument arg) task = rtems_capture_next_task (task); } - fprintf(stdout,"\x1b[4;0H"); - - total_time = 0; - - for (i = 0; i < RTEMS_CAPTURE_CLI_MAX_LOAD_TASKS; i++) - total_time += load[i]; + fprintf (stdout, "\x1b[H\x1b[J Press ENTER to exit.\n\n"); + fprintf (stdout, + " PID NAME RPRI CPRI STATE %%CPU %%STK FLGS EXEC TIME\n"); if (count > last_count) j = count; @@ -395,8 +390,9 @@ rtems_capture_cli_task_load_thread (rtems_task_argument arg) j--; - stack_used = rtems_capture_task_stack_usage (tasks[i]) * 100; - stack_used /= rtems_capture_task_stack_size (tasks[i]); + stack_used = rtems_capture_task_stack_usage (tasks[i]); + if (stack_used) + stack_used = (stack_used * 100) / stack_used; if (stack_used > 100) stack_used = 100; @@ -405,33 +401,32 @@ rtems_capture_cli_task_load_thread (rtems_task_argument arg) priority = rtems_capture_task_real_priority (tasks[i]); - fprintf(stdout,"\x1b[K"); + fprintf (stdout, "\x1b[K"); rtems_monitor_dump_id (rtems_capture_task_id (tasks[i])); - fprintf(stdout," "); + fprintf (stdout, " "); rtems_monitor_dump_name (rtems_capture_task_name (tasks[i])); - fprintf(stdout," "); + fprintf (stdout, " "); rtems_monitor_dump_priority (priority); - fprintf(stdout," "); + fprintf (stdout, " "); rtems_monitor_dump_priority (rtems_capture_task_curr_priority (tasks[i])); - fprintf(stdout," "); + fprintf (stdout, " "); k = rtems_monitor_dump_state (rtems_capture_task_state (tasks[i])); - fprintf(stdout,"%*c %3i.%03i%% ", 6 - k, ' ', task_load / 1000, task_load % 1000); - fprintf(stdout,"%3i%% %c%c%c%c%c", stack_used, + fprintf (stdout, "%*c %3i.%03i%% ", 6 - k, ' ', + task_load / 1000, task_load % 1000); + fprintf (stdout, "%3i%% %c%c", stack_used, rtems_capture_task_valid (tasks[i]) ? 'a' : 'd', - rtems_capture_task_flags (tasks[i]) & RTEMS_CAPTURE_TRACED ? 't' : '-', - rtems_capture_task_control_flags (tasks[i]) & RTEMS_CAPTURE_TO_ANY ? 'F' : '-', - rtems_capture_task_control_flags (tasks[i]) & RTEMS_CAPTURE_FROM_ANY ? 'T' : '-', - rtems_capture_task_control_flags (tasks[i]) & RTEMS_CAPTURE_FROM_TO ? 'E' : '-'); + rtems_capture_task_flags (tasks[i]) & RTEMS_CAPTURE_TRACED ? 't' : '-'); + if ((floor > ceiling) && (ceiling > priority)) - fprintf(stdout,"--"); + fprintf (stdout, "--"); else - fprintf(stdout,"%c%c", + fprintf (stdout, "%c%c", rtems_capture_task_control (tasks[i]) ? (rtems_capture_task_control_flags (tasks[i]) & RTEMS_CAPTURE_WATCH ? 'w' : '+') : '-', rtems_capture_watch_global_on () ? 'g' : '-'); - fprintf(stdout," %qi\n", rtems_capture_task_time (tasks[i])); + fprintf (stdout, " %qi\n", rtems_capture_task_time (tasks[i])); } if (count < RTEMS_CAPTURE_CLI_MAX_LOAD_TASKS) @@ -439,7 +434,7 @@ rtems_capture_cli_task_load_thread (rtems_task_argument arg) j = RTEMS_CAPTURE_CLI_MAX_LOAD_TASKS - count; while (j > 0) { - fprintf(stdout,"\x1b[K\n"); + fprintf (stdout, "\x1b[K\n"); j--; } } @@ -462,11 +457,10 @@ rtems_capture_cli_task_load_thread (rtems_task_argument arg) */ static void -rtems_capture_cli_task_load ( - int argc, - char **argv, - rtems_monitor_command_arg_t *command_arg, - boolean verbose ) +rtems_capture_cli_task_load (int argc, + char** argv, + rtems_monitor_command_arg_t* command_arg, + boolean verbose) { rtems_status_code sc; rtems_task_priority priority; @@ -477,20 +471,22 @@ rtems_capture_cli_task_load ( if (sc != RTEMS_SUCCESSFUL) { - fprintf(stdout,"error: cannot obtain the current priority: %s\n", rtems_status_text (sc)); + fprintf (stdout, "error: cannot obtain the current priority: %s\n", + rtems_status_text (sc)); return; } - memcpy (&name, "CPlt", 4); - - sc = rtems_task_create (name, priority, 1024, + 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) + + if (sc != RTEMS_SUCCESSFUL) { - fprintf(stdout,"error: cannot create helper thread: %s\n", rtems_status_text (sc)); + fprintf (stdout, "error: cannot create helper thread: %s\n", + rtems_status_text (sc)); return; } @@ -498,7 +494,8 @@ rtems_capture_cli_task_load ( if (sc != RTEMS_SUCCESSFUL) { - fprintf(stdout,"error: cannot start helper thread: %s\n", rtems_status_text (sc)); + fprintf (stdout, "error: cannot start helper thread: %s\n", + rtems_status_text (sc)); rtems_task_delete (id); return; } @@ -516,7 +513,7 @@ rtems_capture_cli_task_load ( rtems_task_delete (id); - fprintf(stdout,"load monitoring stopped.\n"); + fprintf (stdout, "load monitoring stopped.\n"); return; } @@ -533,63 +530,81 @@ rtems_capture_cli_task_load ( */ static void -rtems_capture_cli_watch_list ( - int argc, - char **argv, - rtems_monitor_command_arg_t *command_arg, - boolean verbose ) +rtems_capture_cli_watch_list (int argc, + char** argv, + rtems_monitor_command_arg_t* command_arg, + boolean verbose) { rtems_capture_control_t* control = rtems_capture_get_control_list (); rtems_task_priority ceiling = rtems_capture_watch_get_ceiling (); rtems_task_priority floor = rtems_capture_watch_get_floor (); - fprintf(stdout,"watch priority ceiling is %" PRId32 "\n", ceiling); - fprintf(stdout,"watch priority floor is %" PRId32 "\n", floor); - fprintf(stdout,"global watch is %s\n", + fprintf (stdout, "watch priority ceiling is %" PRId32 "\n", ceiling); + fprintf (stdout, "watch priority floor is %" PRId32 "\n", floor); + fprintf (stdout, "global watch is %s\n", rtems_capture_watch_global_on () ? "enabled" : "disabled"); - fprintf(stdout,"total %" PRId32 "\n", rtems_capture_control_count ()); + fprintf (stdout, "total %" PRId32 "\n", rtems_capture_control_count ()); while (control) { - int f; - int fshowed; - int lf; + uint32_t flags; + int f; + int fshowed; + int lf; - fprintf(stdout," "); + fprintf (stdout, " "); rtems_monitor_dump_id (rtems_capture_control_id (control)); - fprintf(stdout," "); + fprintf (stdout, " "); rtems_monitor_dump_name (rtems_capture_control_name (control)); - fprintf(stdout," %c%c%c%c%c", - rtems_capture_control_flags (control) & RTEMS_CAPTURE_WATCH ? 'w' : '-', - rtems_capture_watch_global_on () ? 'g' : '-', - rtems_capture_control_flags (control) & RTEMS_CAPTURE_TO_ANY ? 'F' : '-', - rtems_capture_control_flags (control) & RTEMS_CAPTURE_FROM_ANY ? 'T' : '-', - rtems_capture_control_flags (control) & RTEMS_CAPTURE_FROM_TO ? 'E' : '-'); + flags = rtems_capture_control_flags (control); + fprintf (stdout, " %c%c ", + rtems_capture_watch_global_on () ? 'g' : '-', + flags & RTEMS_CAPTURE_WATCH ? 'w' : '-'); + flags = rtems_capture_control_to_triggers (control); + fprintf (stdout, " T:%c%c%c%c%c%c%c", + flags & RTEMS_CAPTURE_SWITCH ? 'S' : '-', + flags & RTEMS_CAPTURE_CREATE ? 'C' : '-', + flags & RTEMS_CAPTURE_START ? 'S' : '-', + flags & RTEMS_CAPTURE_RESTART ? 'R' : '-', + flags & RTEMS_CAPTURE_DELETE ? 'D' : '-', + flags & RTEMS_CAPTURE_BEGIN ? 'B' : '-', + flags & RTEMS_CAPTURE_EXITTED ? 'E' : '-'); + flags = rtems_capture_control_from_triggers (control); + fprintf (stdout, " F:%c%c%c%c%c", + flags & RTEMS_CAPTURE_SWITCH ? 'S' : '-', + flags & RTEMS_CAPTURE_CREATE ? 'C' : '-', + flags & RTEMS_CAPTURE_START ? 'S' : '-', + flags & RTEMS_CAPTURE_RESTART ? 'R' : '-', + flags & RTEMS_CAPTURE_DELETE ? 'D' : '-'); for (f = 0, fshowed = 0, lf = 1; f < RTEMS_CAPTURE_TRIGGER_TASKS; f++) { - if (lf && ((fshowed % 16) == 0)) + if (rtems_capture_control_by_valid (control, f)) { - fprintf(stdout,"\n"); - lf = 0; - } + if (lf && ((fshowed % 3) == 0)) + { + fprintf (stdout, "\n"); + lf = 0; + } - /* - * FIXME: name test. - */ - if (rtems_capture_control_from_name (control, f)) - { - fprintf(stdout," %2i:", f); - rtems_monitor_dump_name (rtems_capture_control_from_name (control, f)); - fprintf(stdout,"/"); - rtems_monitor_dump_id (rtems_capture_control_from_id (control, f)); + fprintf (stdout, " %2i:", f); + rtems_monitor_dump_name (rtems_capture_control_by_name (control, f)); + fprintf (stdout, "/"); + rtems_monitor_dump_id (rtems_capture_control_by_id (control, f)); + flags = rtems_capture_control_by_triggers (control, f); + fprintf (stdout, ":%c%c%c%c%c", + flags & RTEMS_CAPTURE_SWITCH ? 'S' : '-', + flags & RTEMS_CAPTURE_CREATE ? 'C' : '-', + flags & RTEMS_CAPTURE_START ? 'S' : '-', + flags & RTEMS_CAPTURE_RESTART ? 'R' : '-', + flags & RTEMS_CAPTURE_DELETE ? 'D' : '-'); fshowed++; lf = 1; } } if (lf) - fprintf(stdout,"\n"); + fprintf (stdout, "\n"); control = rtems_capture_next_control (control); } @@ -611,13 +626,12 @@ rtems_capture_cli_get_name_id (char* arg, rtems_name* name, rtems_id* id) { - uint32_t objclass; - size_t l; - size_t i; + size_t l; + size_t i; if (*valid_name && *valid_id) { - fprintf(stdout,"error: too many arguments\n"); + fprintf (stdout, "error: too many arguments\n"); return 0; } @@ -631,15 +645,26 @@ rtems_capture_cli_get_name_id (char* arg, if (!isxdigit (arg[i])) break; - *id = strtoul (arg, 0, 16); - - objclass = _Objects_Get_class (*id); - - if ((i == l)) + if (i == l) + { + *id = strtoul (arg, 0, 16); *valid_id = 1; + } else { - memcpy (name, arg, sizeof (rtems_name)); + /* + * 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. + */ + Objects_Name object_name; + rtems_name rname; + + rname = rtems_build_name(arg[0], arg[1], arg[2], arg[3]); + object_name = (Objects_Name) rname; + *name = (rtems_name) object_name; *valid_name = 1; } @@ -659,11 +684,10 @@ rtems_capture_cli_get_name_id (char* arg, static char const * watch_add_usage = "usage: cwadd [task name] [id]\n"; static void -rtems_capture_cli_watch_add ( - int argc, - char **argv, - rtems_monitor_command_arg_t *command_arg, - boolean verbose ) +rtems_capture_cli_watch_add (int argc, + char** argv, + rtems_monitor_command_arg_t* command_arg, + boolean verbose) { rtems_status_code sc; int arg; @@ -674,7 +698,7 @@ rtems_capture_cli_watch_add ( if (argc <= 1) { - fprintf(stdout,watch_add_usage); + fprintf (stdout, watch_add_usage); return; } @@ -682,18 +706,19 @@ rtems_capture_cli_watch_add ( { if (argv[arg][0] == '-') { - fprintf(stdout,"warning: option -%c ignored\n", argv[arg][1]); + 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)) + 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"); + fprintf (stdout, "error: no valid name or task id located\n"); return; } @@ -701,11 +726,12 @@ rtems_capture_cli_watch_add ( if (sc != RTEMS_SUCCESSFUL) { - fprintf(stdout,"error: watch add failed: %s\n", rtems_status_text (sc)); + fprintf (stdout, + "error: watch add failed: %s\n", rtems_status_text (sc)); return; } - fprintf(stdout,"watch added.\n"); + fprintf (stdout, "watch added.\n"); } /* @@ -721,11 +747,10 @@ rtems_capture_cli_watch_add ( static char const * watch_del_usage = "usage: cwdel [task name] [id]\n"; static void -rtems_capture_cli_watch_del ( - int argc, - char **argv, - rtems_monitor_command_arg_t *command_arg, - boolean verbose ) +rtems_capture_cli_watch_del (int argc, + char** argv, + rtems_monitor_command_arg_t* command_arg, + boolean verbose) { rtems_status_code sc; int arg; @@ -736,7 +761,7 @@ rtems_capture_cli_watch_del ( if (argc <= 1) { - fprintf(stdout,watch_del_usage); + fprintf (stdout, watch_del_usage); return; } @@ -744,18 +769,19 @@ rtems_capture_cli_watch_del ( { if (argv[arg][0] == '-') { - fprintf(stdout,"warning: option -%c ignored\n", argv[arg][1]); + 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)) + 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"); + fprintf (stdout, "error: no valid name or task id located\n"); return; } @@ -763,11 +789,12 @@ rtems_capture_cli_watch_del ( if (sc != RTEMS_SUCCESSFUL) { - fprintf(stdout,"error: watch delete failed: %s\n", rtems_status_text (sc)); + fprintf (stdout, "error: watch delete failed: %s\n", + rtems_status_text (sc)); return; } - fprintf(stdout,"watch delete.\n"); + fprintf (stdout, "watch delete.\n"); } /* @@ -782,11 +809,10 @@ rtems_capture_cli_watch_del ( 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, - rtems_monitor_command_arg_t *command_arg, - boolean verbose ) +rtems_capture_cli_watch_control (int argc, + char** argv, + rtems_monitor_command_arg_t* command_arg, + boolean verbose) { rtems_status_code sc; int arg; @@ -798,7 +824,7 @@ rtems_capture_cli_watch_control ( if (argc <= 2) { - fprintf(stdout,watch_control_usage); + fprintf (stdout, watch_control_usage); return; } @@ -806,7 +832,7 @@ rtems_capture_cli_watch_control ( { if (argv[arg][0] == '-') { - fprintf(stdout,"warning: option -%c ignored\n", argv[arg][1]); + fprintf (stdout, "warning: option -%c ignored\n", argv[arg][1]); } else { @@ -814,14 +840,15 @@ rtems_capture_cli_watch_control ( enable = 1; else if (strcmp (argv[arg], "off") == 0) enable = 0; - else if (!rtems_capture_cli_get_name_id (argv[arg], &valid_name, &valid_id, &name, &id)) + 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"); + fprintf (stdout, "error: no valid name or task id located\n"); return; } @@ -829,11 +856,12 @@ rtems_capture_cli_watch_control ( if (sc != RTEMS_SUCCESSFUL) { - fprintf(stdout,"error: watch control failed: %s\n", rtems_status_text (sc)); + fprintf (stdout, "error: watch control failed: %s\n", + rtems_status_text (sc)); return; } - fprintf(stdout,"watch %s.\n", enable ? "enabled" : "disabled"); + fprintf (stdout, "watch %s.\n", enable ? "enabled" : "disabled"); } /* @@ -848,11 +876,10 @@ rtems_capture_cli_watch_control ( static char const * watch_global_usage = "usage: cwglob on/off\n"; static void -rtems_capture_cli_watch_global ( - int argc, - char **argv, - rtems_monitor_command_arg_t *command_arg, - boolean verbose ) +rtems_capture_cli_watch_global (int argc, + char** argv, + rtems_monitor_command_arg_t* command_arg, + boolean verbose) { rtems_status_code sc; int arg; @@ -860,7 +887,7 @@ rtems_capture_cli_watch_global ( if (argc <= 1) { - fprintf(stdout,watch_global_usage); + fprintf (stdout, watch_global_usage); return; } @@ -868,7 +895,7 @@ rtems_capture_cli_watch_global ( { if (argv[arg][0] == '-') { - fprintf(stdout,"warning: option -%c ignored\n", argv[arg][1]); + fprintf (stdout, "warning: option -%c ignored\n", argv[arg][1]); } else { @@ -883,11 +910,12 @@ rtems_capture_cli_watch_global ( if (sc != RTEMS_SUCCESSFUL) { - fprintf(stdout,"error: global watch failed: %s\n", rtems_status_text (sc)); + fprintf (stdout, "error: global watch failed: %s\n", + rtems_status_text (sc)); return; } - fprintf(stdout,"global watch %s.\n", enable ? "enabled" : "disabled"); + fprintf (stdout, "global watch %s.\n", enable ? "enabled" : "disabled"); } /* @@ -902,11 +930,10 @@ rtems_capture_cli_watch_global ( static char const * watch_ceiling_usage = "usage: cwceil priority\n"; static void -rtems_capture_cli_watch_ceiling ( - int argc, - char **argv, - rtems_monitor_command_arg_t *command_arg, - boolean verbose ) +rtems_capture_cli_watch_ceiling (int argc, + char** argv, + rtems_monitor_command_arg_t* command_arg, + boolean verbose) { rtems_status_code sc; int arg; @@ -914,7 +941,7 @@ rtems_capture_cli_watch_ceiling ( if (argc <= 1) { - fprintf(stdout,watch_ceiling_usage); + fprintf (stdout, watch_ceiling_usage); return; } @@ -922,7 +949,7 @@ rtems_capture_cli_watch_ceiling ( { if (argv[arg][0] == '-') { - fprintf(stdout,"warning: option -%c ignored\n", argv[arg][1]); + fprintf (stdout, "warning: option -%c ignored\n", argv[arg][1]); } else { @@ -934,11 +961,12 @@ rtems_capture_cli_watch_ceiling ( if (sc != RTEMS_SUCCESSFUL) { - fprintf(stdout,"error: watch ceiling failed: %s\n", rtems_status_text (sc)); + fprintf (stdout, "error: watch ceiling failed: %s\n", + rtems_status_text (sc)); return; } - fprintf(stdout,"watch ceiling is %" PRId32 ".\n", priority); + fprintf (stdout, "watch ceiling is %" PRId32 ".\n", priority); } /* @@ -953,11 +981,10 @@ rtems_capture_cli_watch_ceiling ( static char const * watch_floor_usage = "usage: cwfloor priority\n"; static void -rtems_capture_cli_watch_floor ( - int argc, - char **argv, - rtems_monitor_command_arg_t *command_arg, - boolean verbose ) +rtems_capture_cli_watch_floor (int argc, + char** argv, + rtems_monitor_command_arg_t* command_arg, + boolean verbose) { rtems_status_code sc; int arg; @@ -965,7 +992,7 @@ rtems_capture_cli_watch_floor ( if (argc <= 1) { - fprintf(stdout,watch_floor_usage); + fprintf (stdout, watch_floor_usage); return; } @@ -973,7 +1000,7 @@ rtems_capture_cli_watch_floor ( { if (argv[arg][0] == '-') { - fprintf(stdout,"warning: option -%c ignored\n", argv[arg][1]); + fprintf (stdout, "warning: option -%c ignored\n", argv[arg][1]); } else { @@ -985,169 +1012,277 @@ rtems_capture_cli_watch_floor ( if (sc != RTEMS_SUCCESSFUL) { - fprintf(stdout,"error: watch floor failed: %s\n", rtems_status_text (sc)); + fprintf (stdout, "error: watch floor failed: %s\n", + rtems_status_text (sc)); return; } - fprintf(stdout,"watch floor is %" PRId32 ".\n", priority); + fprintf (stdout, "watch floor is %" PRId32 ".\n", priority); } /* - * rtems_capture_cli_trigger_set + * rtems_capture_cli_trigger_worker * * DESCRIPTION: * - * This function is a monitor command that sets a trigger. + * This function is a monitor command that sets or clears a trigger. * */ -static char const *trigger_set_usage = "usage: ctrig type [from] [fromid] [to] [to id]\n"; +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"; -static void -rtems_capture_cli_trigger_set ( - int argc, - char **argv, - rtems_monitor_command_arg_t *command_arg, - boolean verbose ) +/* + * Structure to handle the parsing of the trigger command line. + */ +typedef struct rtems_capture_cli_triggers_s { - rtems_status_code sc; - int arg; - rtems_capture_trigger_t trigger = rtems_capture_from_to; - rtems_boolean trigger_set = 0; - rtems_name name = 0; - rtems_id id = 0; - rtems_boolean valid_name = 0; - rtems_boolean valid_id = 0; - rtems_name from_name = 0; - rtems_id from_id = 0; - rtems_boolean from_valid_name = 0; - rtems_boolean from_valid_id = 0; - rtems_name to_name = 0; - rtems_id to_id = 0; - rtems_boolean to_valid_name = 0; - rtems_boolean to_valid_id = 0; + char const * name; + rtems_capture_trigger_t type; + int to_only; +} rtems_capture_cli_triggers_t; - if (argc <= 2) - { - fprintf(stdout,trigger_set_usage); - return; - } +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; + rtems_boolean trigger_set = 0; + rtems_boolean is_from = 0; + rtems_name name = 0; + rtems_id id = 0; + rtems_boolean valid_name = 0; + rtems_boolean valid_id = 0; + rtems_name from_name = 0; + rtems_id from_id = 0; + rtems_boolean from_valid_name = 0; + rtems_boolean from_valid_id = 0; + rtems_name to_name = 0; + rtems_id to_id = 0; + rtems_boolean to_valid_name = 0; + rtems_boolean to_valid_id = 0; for (arg = 1; arg < argc; arg++) { if (argv[arg][0] == '-') { - fprintf(stdout,"warning: option -%c ignored\n", argv[arg][1]); + 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) { - if (strcmp (argv[arg], "from") == 0) - trigger = rtems_capture_to_any; - else if (strcmp (argv[arg], "to") == 0) - trigger = rtems_capture_from_any; - else if (strcmp (argv[arg], "edge") == 0) - trigger = rtems_capture_from_any; - else - { - fprintf(stdout,"error: the first argument is the trigger type (from/to/edge)\n"); - return; - } + rtems_boolean found = 0; + 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 = 1; + break; + } + trigger_set = 1; + + /* + * If a trigger was not found assume the default and + * assume the parameter is a task name or id. + */ + if (found) + continue; } - else + + if (strcmp (arg[argv], "from") == 0) + { + if (is_from) + fprintf (stdout, "warning: extra 'from' ignored\n"); + + is_from = 1; + continue; + } + + if (!rtems_capture_cli_get_name_id (argv[arg], &valid_name, &valid_id, + &name, &id)) + return; + + if (valid_name) { - if (trigger == rtems_capture_to_any) + if (is_from) { - if (from_valid_name && from_valid_id) - fprintf(stdout,"warning: extra arguments ignored\n"); - else if (!rtems_capture_cli_get_name_id (argv[arg], &from_valid_name, &from_valid_id, - &from_name, &from_id)) - return; + if (!from_valid_name && !from_valid_id) + { + from_valid_name = 1; + from_name = name; + } + else + fprintf (stdout, "warning: extra arguments ignored\n"); } - else if (trigger == rtems_capture_from_any) + else if (!to_valid_name && !to_valid_id) { - if (to_valid_name && to_valid_id) - fprintf(stdout,"warning: extra arguments ignored\n"); - else if (!rtems_capture_cli_get_name_id (argv[arg], &to_valid_name, &to_valid_id, - &to_name, &to_id)) - return; + to_valid_name = 1; + to_name = name; } - else if (trigger == rtems_capture_from_to) + else + fprintf (stdout, "warning: extra arguments ignored\n"); + } + + if (valid_id) + { + if (is_from) { - if (from_valid_name && from_valid_id && to_valid_name && to_valid_id) - fprintf(stdout,"warning: extra arguments ignored\n"); - else + if (!from_valid_name && !from_valid_id) { - if (!rtems_capture_cli_get_name_id (argv[arg], &valid_name, &valid_id, - &name, &id)) - return; - - if (valid_name) - { - if (!from_valid_name && !from_valid_id) - { - from_valid_name = 1; - from_name = name; - } - else if (to_valid_name) - fprintf(stdout,"warning: extra arguments ignored\n"); - else - { - to_valid_name = 1; - to_name = name; - } - } - if (valid_id) - { - if (!from_valid_id && !to_valid_name) - { - from_valid_id = 1; - from_id = id; - } - else if (to_valid_id) - fprintf(stdout,"warning: extra arguments ignored\n"); - else - { - to_valid_id = 1; - to_id = id; - } - } + from_valid_id = 1; + from_id = id; } + else + fprintf (stdout, "warning: extra arguments ignored\n"); + } + else if (!to_valid_name && !to_valid_id) + { + to_valid_id = 1; + to_id = id; } + else + fprintf (stdout, "warning: extra arguments ignored\n"); } } } - if ((trigger == rtems_capture_to_any) && !from_valid_name && !from_valid_id) + 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,"error: a from trigger need a to name or id\n"); + fprintf (stdout, trigger_set_usage); return; } - if ((trigger == rtems_capture_from_any) && !to_valid_name && !to_valid_id) + if (!is_from && !to_valid_name && !to_valid_id) { - fprintf(stdout,"error: a to trigger need a from name or id\n"); + fprintf (stdout, "error: a %s trigger needs a TO name or id\n", + rtems_capture_cli_triggers[trigger].name); return; } - if ((trigger == rtems_capture_from_to) && - ((!from_valid_name && !from_valid_id) || (!to_valid_name && !to_valid_id))) + if (is_from && !from_valid_name && !from_valid_id) { - fprintf(stdout,"error: an edge trigger need a from and to name or id\n"); + fprintf (stdout, "error: a %s trigger needs a FROM name or id\n", + rtems_capture_cli_triggers[trigger].name); return; } - sc = rtems_capture_set_trigger (from_name, from_id, to_name, to_id, trigger); + 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: setting the trigger failed: %s\n", rtems_status_text (sc)); + fprintf (stdout, "error: %sing the trigger failed: %s\n", + set ? "sett" : "clear", rtems_status_text (sc)); return; } - fprintf(stdout,"trigger set.\n"); + 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, + rtems_monitor_command_arg_t* command_arg, + boolean verbose) +{ + 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, + rtems_monitor_command_arg_t* command_arg, + boolean verbose) +{ + rtems_capture_cli_trigger_worker (0, argc, argv); } /* @@ -1160,18 +1295,17 @@ rtems_capture_cli_trigger_set ( */ static void -rtems_capture_cli_trace_records ( - int argc, - char **argv, - rtems_monitor_command_arg_t *command_arg, - boolean verbose ) +rtems_capture_cli_trace_records (int argc, + char** argv, + rtems_monitor_command_arg_t* command_arg, + boolean verbose) { rtems_status_code sc; rtems_boolean csv = 0; - static int dump_total = 32; + static int dump_total = 22; int total; int count; - uint32_t read; + uint32_t read; rtems_capture_record_t* rec; int arg; @@ -1181,31 +1315,24 @@ rtems_capture_cli_trace_records ( { if (argv[arg][1] == 'c') csv = 1; - else if (argv[arg][1] == 'r') - { - int i; - int l; + else + fprintf (stdout, "warning: option -%c ignored\n", argv[arg][1]); + } + else + { + int i; + int l; + + l = strlen (argv[arg]); - arg++; - if (arg == argc) + for (i = 0; i < l; i++) + if (!isdigit (argv[arg][i])) { - fprintf(stdout,"error: option -r requires number\n"); + fprintf (stdout, "error: not a number\n"); return; } - l = strlen (argv[arg]); - - for (i = 0; i < l; i++) - if (!isdigit (argv[arg][i])) - { - fprintf(stdout,"error: option -r requires number and currently it is not\n"); - return; - } - - dump_total = strtoul (argv[arg], 0, 0); - } - else - fprintf(stdout,"warning: option -%c ignored\n", argv[arg][1]); + dump_total = strtoul (argv[arg], 0, 0); } } @@ -1217,18 +1344,28 @@ rtems_capture_cli_trace_records ( if (sc != RTEMS_SUCCESSFUL) { - fprintf(stdout,"error: trace read failed: %s\n", rtems_status_text (sc)); + fprintf (stdout, "error: trace read failed: %s\n", rtems_status_text (sc)); rtems_capture_flush (0); return; } + /* + * If we have no records then just exist. We still need to release + * the reader lock. + */ + if (read == 0) + { + rtems_capture_release (read); break; + } - for (count = 0; count < read; count++, rec++) + count = total < read ? total : read; + + while (count--) { if (csv) - fprintf(stdout,"%08" PRIx32 ",%03" PRIu32 + fprintf (stdout, "%08" PRIx32 ",%03" PRIu32 ",%03" PRIu32 ",%04" PRIx32 ",%" PRId32 ",%" PRId32 "\n", (uint32_t) rec->task, (rec->events >> RTEMS_CAPTURE_REAL_PRIORITY_EVENT) & 0xff, @@ -1251,12 +1388,12 @@ rtems_capture_cli_trace_records ( { if (event & 1) { - fprintf(stdout,"%9li.%06li ", (unsigned long) (t / 1000000), + fprintf (stdout, "%9li.%06li ", (unsigned long) (t / 1000000), (unsigned long) (t % 1000000)); rtems_monitor_dump_id (rtems_capture_task_id (rec->task)); - fprintf(stdout," "); + fprintf (stdout, " "); rtems_monitor_dump_name (rtems_capture_task_name (rec->task)); - fprintf(stdout," %3" PRId32 " %3" PRId32 " %s\n", + fprintf (stdout, " %3" PRId32 " %3" PRId32 " %s\n", (rec->events >> RTEMS_CAPTURE_REAL_PRIORITY_EVENT) & 0xff, (rec->events >> RTEMS_CAPTURE_CURR_PRIORITY_EVENT) & 0xff, rtems_capture_event_text (e)); @@ -1264,14 +1401,17 @@ rtems_capture_cli_trace_records ( event >>= 1; } } + rec++; } - if (read < total) - total -= read; + count = total < read ? total : read; + + if (count < total) + total -= count; else total = 0; - rtems_capture_release (read); + rtems_capture_release (count); } } @@ -1286,11 +1426,10 @@ rtems_capture_cli_trace_records ( */ static void -rtems_capture_cli_flush ( - int argc, - char **argv, - rtems_monitor_command_arg_t *command_arg, - boolean verbose ) +rtems_capture_cli_flush (int argc, + char** argv, + rtems_monitor_command_arg_t* command_arg, + boolean verbose) { rtems_status_code sc; rtems_boolean prime = 1; @@ -1303,7 +1442,7 @@ rtems_capture_cli_flush ( if (argv[arg][1] == 'n') prime = 0; else - fprintf(stdout,"warning: option -%c ignored\n", argv[arg][1]); + fprintf (stdout, "warning: option -%c ignored\n", argv[arg][1]); } } @@ -1311,11 +1450,12 @@ rtems_capture_cli_flush ( if (sc != RTEMS_SUCCESSFUL) { - fprintf(stdout,"error: flush failed: %s\n", rtems_status_text (sc)); + fprintf (stdout, "error: flush failed: %s\n", rtems_status_text (sc)); return; } - fprintf(stdout,"trace buffer flushed and %s.\n", prime ? "primed" : "not primed"); + fprintf (stdout, "trace buffer flushed and %s.\n", + prime ? "primed" : "not primed"); } static rtems_monitor_command_entry_t rtems_capture_cli_cmds[] = @@ -1433,14 +1573,22 @@ static rtems_monitor_command_entry_t rtems_capture_cli_cmds[] = 0 }, { - "ctrig", - "usage: ctrig type [from name] [from id] [to name] [to id]\n", + "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, diff --git a/cpukit/libmisc/capture/capture.c b/cpukit/libmisc/capture/capture.c index 3e571382f5..e8c6396490 100644 --- a/cpukit/libmisc/capture/capture.c +++ b/cpukit/libmisc/capture/capture.c @@ -38,7 +38,11 @@ /* * These events are always recorded and are not part of the * watch filters. + * + * This feature has been disabled as it becomes confusing when + * setting up filters and some event leak. */ +#if defined (RTEMS_CAPTURE_ENGINE_ALLOW_RELATED_EVENTS) #define RTEMS_CAPTURE_RECORD_EVENTS (RTEMS_CAPTURE_CREATED_BY_EVENT | \ RTEMS_CAPTURE_CREATED_EVENT | \ RTEMS_CAPTURE_STARTED_BY_EVENT | \ @@ -49,6 +53,9 @@ RTEMS_CAPTURE_DELETED_EVENT | \ RTEMS_CAPTURE_BEGIN_EVENT | \ RTEMS_CAPTURE_EXITTED_EVENT) +#else +#define RTEMS_CAPTURE_RECORD_EVENTS (0) +#endif /* * Global capture flags. @@ -60,16 +67,17 @@ #define RTEMS_CAPTURE_READER_ACTIVE (1 << 4) #define RTEMS_CAPTURE_READER_WAITING (1 << 5) #define RTEMS_CAPTURE_GLOBAL_WATCH (1 << 6) +#define RTEMS_CAPTURE_ONLY_MONITOR (1 << 7) /* * RTEMS Capture Data. */ static rtems_capture_record_t* capture_records; -static uint32_t capture_size; -static uint32_t capture_count; +static uint32_t capture_size; +static uint32_t capture_count; static rtems_capture_record_t* capture_in; -static uint32_t capture_out; -static uint32_t capture_flags; +static uint32_t capture_out; +static uint32_t capture_flags; static rtems_capture_task_t* capture_tasks; static rtems_capture_control_t* capture_controls; static int capture_extension_index; @@ -77,9 +85,8 @@ static rtems_id capture_id; static rtems_capture_timestamp capture_timestamp; static rtems_task_priority capture_ceiling; static rtems_task_priority capture_floor; -static uint32_t capture_tick_period; +static uint32_t capture_tick_period; static rtems_id capture_reader; -int rtems_capture_free_info_on_task_delete; /* * RTEMS Event text. @@ -109,8 +116,8 @@ static const char* capture_event_text[] = * This function returns the current time. If a handler is provided * by the user get the time from that. */ -static inline void rtems_capture_get_time (uint32_t * ticks, - uint32_t * tick_offset) +static inline void rtems_capture_get_time (uint32_t* ticks, + uint32_t* tick_offset) { if (capture_timestamp) capture_timestamp (ticks, tick_offset); @@ -138,6 +145,48 @@ rtems_capture_match_names (rtems_name lhs, rtems_name rhs) } /* + * rtems_capture_match_id + * + * DESCRIPTION: + * + * This function compares rtems_ids. It protects the + * capture engine from a change to the way id are supported + * in RTEMS. + * + */ +static inline rtems_boolean +rtems_capture_match_ids (rtems_id lhs, rtems_id rhs) +{ + return lhs == rhs; +} + +/* + * rtems_capture_match_name_id + * + * DESCRIPTION: + * + * This function matches a name and/or id. + */ +static inline rtems_boolean +rtems_capture_match_name_id (rtems_name lhs_name, + rtems_id lhs_id, + rtems_name rhs_name, + rtems_id rhs_id) +{ + /* + * The left hand side name or id could be 0 which means a wildcard. + */ + if ((lhs_name == 0) && (lhs_id == rhs_id)) + return 1; + else if ((lhs_id == 0) || (lhs_id == rhs_id)) + { + if (rtems_capture_match_names (lhs_name, rhs_name)) + return 1; + } + return 0; +} + +/* * rtems_capture_dup_name * * DESCRIPTION: @@ -154,50 +203,84 @@ rtems_capture_dup_name (rtems_name* dst, rtems_name src) } /* - * rtems_capture_name_in_group + * rtems_capture_by_in_to * * DESCRIPTION: * - * This function sees if a name is in a group of names. + * This function sees if a BY control is in the BY names. The use + * of the valid_mask in this way assumes the number of trigger + * tasks is the number of bits in uint32_t. * */ static inline rtems_boolean -rtems_capture_name_in_group (rtems_name task, rtems_name* tasks) +rtems_capture_by_in_to (uint32_t events, + rtems_capture_task_t* by, + rtems_capture_control_t* to) { - if (tasks) + uint32_t valid_mask = RTEMS_CAPTURE_CONTROL_FROM_MASK (0); + uint32_t valid_remainder = 0xffffffff; + int i; + + for (i = 0; i < RTEMS_CAPTURE_TRIGGER_TASKS; i++) { - int i; - for (i = 0; i < RTEMS_CAPTURE_TRIGGER_TASKS; i++) - if (rtems_capture_match_names (task, *tasks++)) + /* + * If there are no more valid BY entries then + * we are finished. + */ + if ((valid_remainder & to->by_valid) == 0) + break; + + /* + * Is the froby entry valid and does its name or id match. + */ + if ((valid_mask & to->by_valid) && + (to->by[i].trigger & events)) + { + /* + * We have the BY task on the right hand side so we + * match with id's first then labels if the id's are + * not set. + */ + if (rtems_capture_match_name_id (to->by[i].name, to->by[i].id, + by->name, by->id)) return 1; + } + + valid_mask >>= 1; + valid_remainder >>= 1; } + return 0; } /* - * rtems_capture_match_name_id + * rtems_capture_refcount_up * * DESCRIPTION: * - * This function matches a name and/or id. + * This function raises the reference count. + * */ -static inline rtems_boolean -rtems_capture_match_name_id (rtems_name lhs_name, - rtems_id lhs_id, - rtems_name rhs_name, - rtems_id rhs_id) +static inline void +rtems_capture_refcount_up (rtems_capture_task_t* task) { - /* - * The left hand side name or id could be 0 which means a wildcard. - */ - if ((lhs_name == 0) && (lhs_id == rhs_id)) - return 1; - else if ((lhs_id == 0) || (lhs_id == rhs_id)) - { - if (rtems_capture_match_names (lhs_name, rhs_name)) - return 1; - } - return 0; + task->refcount++; +} + +/* + * rtems_capture_refcount_down + * + * DESCRIPTION: + * + * This function lowers the reference count and if the count + * reaches 0 the task control block is returned to the heap. + * + */ +static inline void +rtems_capture_refcount_down (rtems_capture_task_t* task) +{ + if (task->refcount) + task->refcount--; } /* @@ -212,8 +295,8 @@ rtems_capture_init_stack_usage (rtems_capture_task_t* task) { if (task->tcb) { - uint32_t * s; - uint32_t i; + uint32_t* s; + uint32_t i; task->stack_size = task->tcb->Start.Initial_stack.size; task->stack_clean = task->stack_size; @@ -274,12 +357,14 @@ rtems_capture_create_control (rtems_name name, rtems_id id) return NULL; } - control->name = name; - control->id = id; - control->flags = 0; + control->name = name; + control->id = id; + control->flags = 0; + control->to_triggers = 0; + control->from_triggers = 0; + control->by_valid = 0; - memset (control->from, 0, sizeof (control->from)); - memset (control->from_id, 0, sizeof (control->from_id)); + memset (control->by, 0, sizeof (control->by)); rtems_interrupt_disable (level); @@ -314,7 +399,8 @@ rtems_capture_create_capture_task (rtems_tcb* new_task) rtems_interrupt_level level; rtems_capture_task_t* task; rtems_capture_control_t* control; - + rtems_name name; + task = _Workspace_Allocate (sizeof (rtems_capture_task_t)); if (task == NULL) @@ -323,11 +409,23 @@ rtems_capture_create_capture_task (rtems_tcb* new_task) return NULL; } - rtems_capture_dup_name (&task->name, ((rtems_name) new_task->Object.name)); - + /* + * Check the type of name the object has. + */ + if (_Objects_Get_API (new_task->Object.id) == OBJECTS_CLASSIC_API) + name = (rtems_name) new_task->Object.name; + else + name = rtems_build_name (((char*) new_task->Object.name)[0], + ((char*) new_task->Object.name)[1], + ((char*) new_task->Object.name)[2], + ((char*) new_task->Object.name)[3]); + + rtems_capture_dup_name (&task->name, name); + task->id = new_task->Object.id; task->flags = 0; task->in = 0; + task->refcount = 0; task->out = 0; task->tcb = new_task; task->ticks = 0; @@ -368,6 +466,45 @@ rtems_capture_create_capture_task (rtems_tcb* new_task) } /* + * rtems_capture_destroy_capture_task + * + * DESCRIPTION: + * + * This function destroy the task structure if the reference count + * is 0 and the tcb has been cleared signalling the task has been + * deleted. + * + */ +static inline void +rtems_capture_destroy_capture_task (rtems_capture_task_t* task) +{ + if (task) + { + rtems_interrupt_level level; + + rtems_interrupt_disable (level); + + if (task->tcb || task->refcount) + task = 0; + + if (task) + { + if (task->forw) + task->forw->back = task->back; + if (task->back) + task->back->forw = task->forw; + else + capture_tasks = task->forw; + } + + rtems_interrupt_enable (level); + + if (task) + _Workspace_Free (task); + } +} + +/* * rtems_capture_record * * DESCRIPTION: @@ -377,13 +514,16 @@ rtems_capture_create_capture_task (rtems_tcb* new_task) */ static inline void rtems_capture_record (rtems_capture_task_t* task, - uint32_t events) + uint32_t events) { /* * Check the watch state if we have a task control, and * the task's real priority is lower or equal to the ceiling. */ - if (task) + if (task && + ((capture_flags & + (RTEMS_CAPTURE_TRIGGERED | RTEMS_CAPTURE_ONLY_MONITOR)) == + RTEMS_CAPTURE_TRIGGERED)) { rtems_capture_control_t* control; @@ -422,6 +562,8 @@ rtems_capture_record (rtems_capture_task_t* task, capture_in = capture_records; else capture_in++; + + rtems_capture_refcount_up (task); } else capture_flags |= RTEMS_CAPTURE_OVERFLOW; @@ -431,6 +573,79 @@ rtems_capture_record (rtems_capture_task_t* task, } /* + * rtems_capture_trigger + * + * DESCRIPTION: + * + * See if we have triggered and if not see if this event is a + * cause of a trigger. + */ +rtems_boolean +rtems_capture_trigger (rtems_capture_task_t* ft, + rtems_capture_task_t* tt, + uint32_t events) +{ + /* + * If we have not triggered then see if this is a trigger condition. + */ + if (!(capture_flags & RTEMS_CAPTURE_TRIGGERED)) + { + rtems_capture_control_t* fc = NULL; + rtems_capture_control_t* tc = NULL; + uint32_t from_events = 0; + uint32_t to_events = 0; + uint32_t from_to_events = 0; + + if (ft) + { + fc = ft->control; + if (fc) + from_events = fc->from_triggers & events; + } + + if (tt) + { + tc = tt->control; + if (tc) + { + to_events = tc->to_triggers & events; + if (ft && tc->by_valid) + from_to_events = tc->by_triggers & events; + } + } + + /* + * Check if we have any from or to events. These are the + * from any or to any type triggers. All from/to triggers are + * listed in the to's control with the from in the from list. + * + * The masking above means any flag set is a trigger. + */ + if (from_events || to_events) + { + capture_flags |= RTEMS_CAPTURE_TRIGGERED; + return 1; + } + + /* + * Check the from->to events. + */ + if (from_to_events) + { + if (rtems_capture_by_in_to (events, ft, tc)) + { + capture_flags |= RTEMS_CAPTURE_TRIGGERED; + return 1; + } + } + + return 0; + } + + return 1; +} + +/* * rtems_capture_create_task * * DESCRIPTION: @@ -448,7 +663,7 @@ rtems_capture_create_task (rtems_tcb* current_task, ct = current_task->extensions[capture_extension_index]; /* - * The task ponters may not be known as the task may have + * The task pointers may not be known as the task may have * been created before the capture engine was open. Add them. */ @@ -460,11 +675,11 @@ rtems_capture_create_task (rtems_tcb* current_task, */ nt = rtems_capture_create_capture_task (new_task); - /* - * If we are logging then record this fact. - */ - rtems_capture_record (ct, RTEMS_CAPTURE_CREATED_BY_EVENT); - rtems_capture_record (nt, RTEMS_CAPTURE_CREATED_EVENT); + if (rtems_capture_trigger (ct, nt, RTEMS_CAPTURE_CREATE)) + { + rtems_capture_record (ct, RTEMS_CAPTURE_CREATED_BY_EVENT); + rtems_capture_record (nt, RTEMS_CAPTURE_CREATED_EVENT); + } return 1 == 1; } @@ -492,7 +707,7 @@ rtems_capture_start_task (rtems_tcb* current_task, st = started_task->extensions[capture_extension_index]; /* - * The task ponters may not be known as the task may have + * The task pointers may not be known as the task may have * been created before the capture engine was open. Add them. */ @@ -501,9 +716,12 @@ rtems_capture_start_task (rtems_tcb* current_task, if (st == NULL) st = rtems_capture_create_capture_task (started_task); - - rtems_capture_record (ct, RTEMS_CAPTURE_STARTED_BY_EVENT); - rtems_capture_record (st, RTEMS_CAPTURE_STARTED_EVENT); + + if (rtems_capture_trigger (ct, st, RTEMS_CAPTURE_START)) + { + rtems_capture_record (ct, RTEMS_CAPTURE_STARTED_BY_EVENT); + rtems_capture_record (st, RTEMS_CAPTURE_STARTED_EVENT); + } rtems_capture_init_stack_usage (st); } @@ -531,7 +749,7 @@ rtems_capture_restart_task (rtems_tcb* current_task, rt = restarted_task->extensions[capture_extension_index]; /* - * The task ponters may not be known as the task may have + * The task pointers may not be known as the task may have * been created before the capture engine was open. Add them. */ @@ -541,8 +759,11 @@ rtems_capture_restart_task (rtems_tcb* current_task, if (rt == NULL) rt = rtems_capture_create_capture_task (restarted_task); - rtems_capture_record (ct, RTEMS_CAPTURE_RESTARTED_BY_EVENT); - rtems_capture_record (rt, RTEMS_CAPTURE_RESTARTED_EVENT); + if (rtems_capture_trigger (ct, rt, RTEMS_CAPTURE_RESTART)) + { + rtems_capture_record (ct, RTEMS_CAPTURE_RESTARTED_BY_EVENT); + rtems_capture_record (rt, RTEMS_CAPTURE_RESTARTED_EVENT); + } rtems_capture_task_stack_usage (rt); rtems_capture_init_stack_usage (rt); @@ -568,7 +789,7 @@ rtems_capture_delete_task (rtems_tcb* current_task, rtems_capture_task_t* dt; /* - * The task ponters may not be known as the task may have + * The task pointers may not be known as the task may have * been created before the capture engine was open. Add them. */ @@ -581,28 +802,21 @@ rtems_capture_delete_task (rtems_tcb* current_task, if (dt == NULL) dt = rtems_capture_create_capture_task (deleted_task); - rtems_capture_record (ct, RTEMS_CAPTURE_DELETED_BY_EVENT); - rtems_capture_record (dt, RTEMS_CAPTURE_DELETED_EVENT); - + if (rtems_capture_trigger (ct, dt, RTEMS_CAPTURE_DELETE)) + { + rtems_capture_record (ct, RTEMS_CAPTURE_DELETED_BY_EVENT); + rtems_capture_record (dt, RTEMS_CAPTURE_DELETED_EVENT); + } + rtems_capture_task_stack_usage (dt); /* - * This task's tcb will be invalid. + * This task's tcb will be invalid. This signals the + * task has been deleted. */ dt->tcb = 0; - /* - * Unlink - */ - if (rtems_capture_free_info_on_task_delete) { - if (dt->forw) - dt->forw->back = dt->back; - if (dt->back) - dt->back->forw = dt->forw; - else - capture_tasks = dt->forw; - _Workspace_Free (dt); - } + rtems_capture_destroy_capture_task (dt); } /* @@ -625,14 +839,15 @@ rtems_capture_begin_task (rtems_tcb* begin_task) bt = begin_task->extensions[capture_extension_index]; /* - * The task ponters may not be known as the task may have + * The task pointers may not be known as the task may have * been created before the capture engine was open. Add them. */ if (bt == NULL) bt = rtems_capture_create_capture_task (begin_task); - rtems_capture_record (bt, RTEMS_CAPTURE_BEGIN_EVENT); + if (rtems_capture_trigger (NULL, bt, RTEMS_CAPTURE_BEGIN)) + rtems_capture_record (bt, RTEMS_CAPTURE_BEGIN_EVENT); } /* @@ -656,14 +871,15 @@ rtems_capture_exitted_task (rtems_tcb* exitted_task) et = exitted_task->extensions[capture_extension_index]; /* - * The task ponters may not be known as the task may have + * The task pointers may not be known as the task may have * been created before the capture engine was open. Add them. */ if (et == NULL) et = rtems_capture_create_capture_task (exitted_task); - rtems_capture_record (et, RTEMS_CAPTURE_EXITTED_EVENT); + if (rtems_capture_trigger (NULL, et, RTEMS_CAPTURE_EXITTED)) + rtems_capture_record (et, RTEMS_CAPTURE_EXITTED_EVENT); rtems_capture_task_stack_usage (et); } @@ -686,13 +902,13 @@ rtems_capture_switch_task (rtems_tcb* current_task, */ if (capture_flags & RTEMS_CAPTURE_ON) { - uint32_t ticks; - uint32_t tick_offset; + uint32_t ticks; + uint32_t tick_offset; /* * Get the cpature task control block so we can update the - * reference anbd perform any watch or trigger functions. - * The task ponters may not be known as the task may have + * reference and perform any watch or trigger functions. + * The task pointers may not be known as the task may have * been created before the capture engine was open. Add them. */ rtems_capture_task_t* ct; @@ -760,57 +976,8 @@ rtems_capture_switch_task (rtems_tcb* current_task, } } - /* - * If we have not triggered then see if this is a trigger condition. - */ - if (!(capture_flags & RTEMS_CAPTURE_TRIGGERED)) - { - rtems_capture_control_t* cc = NULL; - rtems_capture_control_t* hc = NULL; - - if (ct) - { - cc = ct->control; - - /* - * Check the current task for a TO_ANY trigger. - */ - if (cc && (cc->flags & RTEMS_CAPTURE_TO_ANY)) - { - capture_flags |= RTEMS_CAPTURE_TRIGGERED; - goto triggered; - } - } - - if (ht) - { - hc = ht->control; - - /* - * Check the next task for a FROM_ANY. - */ - if (hc && (hc->flags & RTEMS_CAPTURE_FROM_ANY)) - { - capture_flags |= RTEMS_CAPTURE_TRIGGERED; - goto triggered; - } - } - - /* - * Check is the trigger is from the current task - * to the next task. - */ - if (cc && hc && (hc->flags & RTEMS_CAPTURE_FROM_TO)) - if (rtems_capture_name_in_group (cc->name, hc->from)) - { - capture_flags |= RTEMS_CAPTURE_TRIGGERED; - goto triggered; - } - } - else + if (rtems_capture_trigger (ct, ht, RTEMS_CAPTURE_SWITCH)) { -triggered: - rtems_capture_record (ct, RTEMS_CAPTURE_SWITCHED_OUT_EVENT); rtems_capture_record (ht, RTEMS_CAPTURE_SWITCHED_IN_EVENT); } @@ -921,7 +1088,7 @@ rtems_capture_close () return RTEMS_SUCCESSFUL; } - capture_flags &= ~RTEMS_CAPTURE_ON; + capture_flags &= ~(RTEMS_CAPTURE_ON | RTEMS_CAPTURE_ONLY_MONITOR); records = capture_records; capture_records = NULL; @@ -1000,6 +1167,38 @@ rtems_capture_control (rtems_boolean enable) } /* + * rtems_capture_monitor + * + * DESCRIPTION: + * + * This function enable the monitor mode. When in the monitor mode + * the tasks are monitored but no data is saved. This can be used + * to profile the load on a system. + */ +rtems_status_code +rtems_capture_monitor (rtems_boolean enable) +{ + rtems_interrupt_level level; + + rtems_interrupt_disable (level); + + if (!capture_records) + { + rtems_interrupt_enable (level); + return RTEMS_UNSATISFIED; + } + + if (enable) + capture_flags |= RTEMS_CAPTURE_ONLY_MONITOR; + else + capture_flags &= ~RTEMS_CAPTURE_ONLY_MONITOR; + + rtems_interrupt_enable (level); + + return RTEMS_SUCCESSFUL; +} + +/* * rtems_capture_flush * * DESCRIPTION: @@ -1016,18 +1215,31 @@ rtems_capture_flush (rtems_boolean prime) rtems_interrupt_disable (level); for (task = capture_tasks; task != NULL; task = task->forw) + { task->flags &= ~RTEMS_CAPTURE_TRACED; + task->refcount = 0; + } if (prime) capture_flags &= ~(RTEMS_CAPTURE_TRIGGERED | RTEMS_CAPTURE_OVERFLOW); else capture_flags &= ~RTEMS_CAPTURE_OVERFLOW; - capture_in = capture_records; - capture_out = 0; - + capture_count = 0; + capture_in = capture_records; + capture_out = 0; + rtems_interrupt_enable (level); + task = capture_tasks; + + while (task) + { + rtems_capture_task_t* check = task; + task = task->forw; + rtems_capture_destroy_capture_task (check); + } + return RTEMS_SUCCESSFUL; } @@ -1088,7 +1300,7 @@ rtems_capture_watch_del (rtems_name name, rtems_id id) for (prev_control = &capture_controls, control = capture_controls; control != NULL; ) { - if (rtems_capture_match_name_id (name, id, control->name, control->id)) + if (rtems_capture_match_name_id (control->name, control->id, name, id)) { rtems_interrupt_disable (level); @@ -1110,7 +1322,7 @@ rtems_capture_watch_del (rtems_name name, rtems_id id) { prev_control = &control->next; control = control->next; - } + } } if (found) @@ -1140,7 +1352,7 @@ rtems_capture_watch_ctrl (rtems_name name, rtems_id id, rtems_boolean enable) */ for (control = capture_controls; control != NULL; control = control->next) { - if (rtems_capture_match_name_id (name, id, control->name, control->id)) + if (rtems_capture_match_name_id (control->name, control->id, name, id)) { rtems_interrupt_disable (level); @@ -1265,18 +1477,47 @@ rtems_capture_watch_get_floor () } /* - * rtems_capture_set_trigger + * rtems_capture_map_trigger * * DESCRIPTION: * - * This function sets an edge trigger. Left is the left side of - * the edge and right is right side of the edge. The trigger type - * can be - + * Map the trigger to a bit mask. * - * FROM_ANY : a switch from any task to the right side of the edge. - * TO_ANY : a switch from the left side of the edge to any task. - * FROM_TO : a switch from the left side of the edge to the right - * side of the edge. + */ +uint32_t +rtems_capture_map_trigger (rtems_capture_trigger_t trigger) +{ + /* + * Transform the mode and trigger to a bit map. + */ + switch (trigger) + { + case rtems_capture_switch: + return RTEMS_CAPTURE_SWITCH; + case rtems_capture_create: + return RTEMS_CAPTURE_CREATE; + case rtems_capture_start: + return RTEMS_CAPTURE_START; + case rtems_capture_restart: + return RTEMS_CAPTURE_RESTART; + case rtems_capture_delete: + return RTEMS_CAPTURE_DELETE; + case rtems_capture_begin: + return RTEMS_CAPTURE_BEGIN; + case rtems_capture_exitted: + return RTEMS_CAPTURE_EXITTED; + default: + break; + } + return 0; +} + +/* + * rtems_capture_set_trigger + * + * DESCRIPTION: + * + * This function sets a trigger. * * This set trigger routine will create a capture control for the * target task. The task list is searched and any existing tasks @@ -1287,48 +1528,149 @@ rtems_capture_watch_get_floor () * linked to single control. */ rtems_status_code -rtems_capture_set_trigger (rtems_name from, - rtems_id from_id, - rtems_name to, - rtems_id to_id, - rtems_capture_trigger_t trigger) +rtems_capture_set_trigger (rtems_name from_name, + rtems_id from_id, + rtems_name to_name, + rtems_id to_id, + rtems_capture_trigger_mode_t mode, + rtems_capture_trigger_t trigger) { rtems_capture_control_t* control; - int i; + uint32_t flags; + + flags = rtems_capture_map_trigger (trigger); /* - * Find the capture control blocks for the from and to - * tasks. + * The mode sets the opposite type of trigger. For example + * FROM ANY means trigger when the event happens TO this + * task. TO ANY means FROM this task. */ - if (trigger == rtems_capture_to_any) + + if (mode == rtems_capture_to_any) { - control = rtems_capture_create_control (from, from_id); + control = rtems_capture_create_control (from_name, from_id); if (control == NULL) return RTEMS_NO_MEMORY; - control->flags |= RTEMS_CAPTURE_TO_ANY; + control->from_triggers |= flags & RTEMS_CAPTURE_FROM_TRIGS; } - - if ((trigger == rtems_capture_from_to) || - (trigger == rtems_capture_from_any)) + else { - control = rtems_capture_create_control (to, to_id); + control = rtems_capture_create_control (to_name, to_id); if (control == NULL) return RTEMS_NO_MEMORY; + if (mode == rtems_capture_from_any) + control->to_triggers |= flags; + else + { + rtems_boolean done = 0; + int i; + + control->by_triggers |= flags; + + for (i = 0; i < RTEMS_CAPTURE_TRIGGER_TASKS; i++) + { + if (rtems_capture_control_by_valid (control, i) && + ((control->by[i].name == from_name) || + (from_id && (control->by[i].id == from_id)))) + { + control->by[i].trigger |= flags; + done = 1; + break; + } + } + + if (!done) + { + for (i = 0; i < RTEMS_CAPTURE_TRIGGER_TASKS; i++) + { + if (!rtems_capture_control_by_valid (control, i)) + { + control->by_valid |= RTEMS_CAPTURE_CONTROL_FROM_MASK (i); + control->by[i].name = from_name; + control->by[i].id = from_id; + control->by[i].trigger = flags; + done = 1; + break; + } + } + } + + if (!done) + return RTEMS_TOO_MANY; + } + } + return RTEMS_SUCCESSFUL; +} - if (trigger == rtems_capture_from_any) - control->flags |= RTEMS_CAPTURE_FROM_ANY; +/* + * rtems_capture_clear_trigger + * + * DESCRIPTION: + * + * This function clear a trigger. + */ +rtems_status_code +rtems_capture_clear_trigger (rtems_name from_name, + rtems_id from_id, + rtems_name to_name, + rtems_id to_id, + rtems_capture_trigger_mode_t mode, + rtems_capture_trigger_t trigger) +{ + rtems_capture_control_t* control; + uint32_t flags; + + flags = rtems_capture_map_trigger (trigger); + + if (mode == rtems_capture_to_any) + { + control = rtems_capture_find_control (from_name, from_id); + if (control == NULL) + { + if (from_id) + return RTEMS_INVALID_ID; + return RTEMS_INVALID_NAME; + } + control->from_triggers &= ~flags; + } + else + { + control = rtems_capture_find_control (to_name, to_id); + if (control == NULL) + { + if (to_id) + return RTEMS_INVALID_ID; + return RTEMS_INVALID_NAME; + } + if (mode == rtems_capture_from_any) + control->to_triggers &= ~flags; else { - control->flags |= RTEMS_CAPTURE_FROM_TO; + rtems_boolean done = 0; + int i; + + control->by_triggers &= ~flags; + for (i = 0; i < RTEMS_CAPTURE_TRIGGER_TASKS; i++) { - if (control->from[i] == 0) + if (rtems_capture_control_by_valid (control, i) && + ((control->by[i].name == from_name) || + (control->by[i].id == from_id))) { - control->from[i] = from; - control->from_id[i] = from_id; + control->by[i].trigger &= ~trigger; + if (control->by[i].trigger == 0) + control->by_valid &= ~RTEMS_CAPTURE_CONTROL_FROM_MASK (i); + done = 1; break; } } + + if (!done) + { + if (from_id) + return RTEMS_INVALID_ID; + return RTEMS_INVALID_NAME; + } } } return RTEMS_SUCCESSFUL; @@ -1366,14 +1708,14 @@ rtems_capture_set_trigger (rtems_name from, * */ rtems_status_code -rtems_capture_read (uint32_t threshold, - uint32_t timeout, - uint32_t * read, +rtems_capture_read (uint32_t threshold, + uint32_t timeout, + uint32_t* read, rtems_capture_record_t** recs) { rtems_interrupt_level level; rtems_status_code sc = RTEMS_SUCCESSFUL; - uint32_t count; + uint32_t count; *read = 0; *recs = NULL; @@ -1455,12 +1797,6 @@ rtems_capture_read (uint32_t threshold, break; } - rtems_interrupt_disable (level); - - capture_flags &= ~RTEMS_CAPTURE_READER_ACTIVE; - - rtems_interrupt_enable (level); - return sc; } @@ -1473,8 +1809,11 @@ rtems_capture_read (uint32_t threshold, * to the capture engine. The count must match the number read. */ rtems_status_code -rtems_capture_release (uint32_t count) +rtems_capture_release (uint32_t count) { + rtems_capture_record_t* rec; + uint32_t counted; + rtems_interrupt_level level; rtems_interrupt_disable (level); @@ -1482,9 +1821,26 @@ rtems_capture_release (uint32_t count) if (count > capture_count) count = capture_count; + rtems_interrupt_enable (level); + + counted = count; + + rec = &capture_records[capture_out]; + + while (counted--) + { + rtems_capture_refcount_down (rec->task); + rtems_capture_destroy_capture_task (rec->task); + rec++; + } + + rtems_interrupt_disable (level); + capture_count -= count; - capture_out = (capture_count + count) % capture_size; + capture_out = (capture_out + count) % capture_size; + + capture_flags &= ~RTEMS_CAPTURE_READER_ACTIVE; rtems_interrupt_enable (level); @@ -1548,8 +1904,8 @@ rtems_capture_task_stack_usage (rtems_capture_task_t* task) { if (task->tcb) { - uint32_t * st; - uint32_t * s; + uint32_t* st; + uint32_t* s; /* * @todo: Assumes all stacks move the same way. @@ -1565,7 +1921,7 @@ rtems_capture_task_stack_usage (rtems_capture_task_t* task) } task->stack_clean = - s - (uint32_t *) task->tcb->Start.Initial_stack.area; + s - (uint32_t*) task->tcb->Start.Initial_stack.area; } return task->stack_clean; diff --git a/cpukit/libmisc/capture/capture.h b/cpukit/libmisc/capture/capture.h index 6db1ee89f3..11b9835e93 100644 --- a/cpukit/libmisc/capture/capture.h +++ b/cpukit/libmisc/capture/capture.h @@ -22,7 +22,6 @@ ------------------------------------------------------------------------ RTEMS Performance Monitoring and Measurement Framework. - This is the Capture Engine component. */ @@ -42,44 +41,100 @@ extern "C" { #define RTEMS_CAPTURE_TRIGGER_TASKS (32) /** + * rtems_capture_from_t + * + * DESCRIPTION: + * + * A from capture is a task id and a mask for the type of + * from trigger we are interested in. The mask uses the same + * bit maps as the flags field in the control structure. There + * will only be a from type trigger if the flags in the control + * structure has the specific *_BY bit set. + */ +typedef struct rtems_capture_from_s +{ + rtems_name name; + rtems_id id; + uint32_t trigger; +} rtems_capture_from_t; + +/** * rtems_capture_control_t * * DESCRIPTION: * * RTEMS control holds the trigger and watch configuration for a group of - * tasks with the same name. + * tasks with the same name. The flags hold global control flags. + * + * The to_triggers fields holds triggers TO this task. The from_triggers holds + * triggers from this task. The by_triggers is an OR or triggers which are + * caused BY the task listed TO this task. The by_valid flag which entries + * in by are valid. */ typedef struct rtems_capture_control_s { rtems_name name; rtems_id id; - uint32_t flags; - rtems_name from[RTEMS_CAPTURE_TRIGGER_TASKS]; - rtems_id from_id[RTEMS_CAPTURE_TRIGGER_TASKS]; + uint32_t flags; + uint32_t to_triggers; + uint32_t from_triggers; + uint32_t by_triggers; + uint32_t by_valid; + rtems_capture_from_t by[RTEMS_CAPTURE_TRIGGER_TASKS]; struct rtems_capture_control_s* next; } rtems_capture_control_t; /** + * The from_valid mask. + */ +#define RTEMS_CAPTURE_CONTROL_FROM_MASK(_s) \ + (1 << (RTEMS_CAPTURE_TRIGGER_TASKS - ((_s) + 1))) + +/** * Control flags. */ #define RTEMS_CAPTURE_WATCH (1 << 0) -#define RTEMS_CAPTURE_FROM_ANY (1 << 1) -#define RTEMS_CAPTURE_TO_ANY (1 << 2) -#define RTEMS_CAPTURE_FROM_TO (1 << 3) /** + * Control triggers. + */ +#define RTEMS_CAPTURE_SWITCH (1 << 0) +#define RTEMS_CAPTURE_CREATE (1 << 1) +#define RTEMS_CAPTURE_START (1 << 2) +#define RTEMS_CAPTURE_RESTART (1 << 3) +#define RTEMS_CAPTURE_DELETE (1 << 4) +#define RTEMS_CAPTURE_BEGIN (1 << 5) +#define RTEMS_CAPTURE_EXITTED (1 << 6) + +#define RTEMS_CAPTURE_FROM_TRIGS (RTEMS_CAPTURE_SWITCH | \ + RTEMS_CAPTURE_CREATE | \ + RTEMS_CAPTURE_START | \ + RTEMS_CAPTURE_RESTART | \ + RTEMS_CAPTURE_DELETE) + +#define RTEMS_CAPTURE_TO_TRIGS (RTEMS_CAPTURE_SWITCH | \ + RTEMS_CAPTURE_CREATE | \ + RTEMS_CAPTURE_START | \ + RTEMS_CAPTURE_RESTART | \ + RTEMS_CAPTURE_DELETE | \ + RTEMS_CAPTURE_BEGIN | \ + RTEMS_CAPTURE_EXITTED) + +/** * rtems_capture_control_t * * DESCRIPTION: * * RTEMS capture control provdes the information about a task, along * with its trigger state. The control is referenced by each - * capture record. This is* information neeed by the decoder. The + * capture record. This is information neeed by the decoder. The * capture record cannot assume the task will exist when the record is * dumped via the target interface so task info needed for tracing is - * copied and held here. + * copied and held here. Once the references in the trace buffer + * have been removed and the task is deleted this structure is + * released back to the heap. * - * The inline heper functions provide more details about the info + * The inline helper functions provide more details about the info * contained in this structure. * * Note, the tracer code exploits the fact an rtems_name is a @@ -89,19 +144,20 @@ typedef struct rtems_capture_task_s { rtems_name name; rtems_id id; - uint32_t flags; + uint32_t flags; + uint32_t refcount; rtems_tcb* tcb; - uint32_t in; - uint32_t out; + uint32_t in; + uint32_t out; rtems_task_priority start_priority; - uint32_t stack_size; - uint32_t stack_clean; - uint32_t ticks; - uint32_t tick_offset; - uint32_t ticks_in; - uint32_t tick_offset_in; - uint32_t last_ticks; - uint32_t last_tick_offset; + uint32_t stack_size; + uint32_t stack_clean; + uint32_t ticks; + uint32_t tick_offset; + uint32_t ticks_in; + uint32_t tick_offset_in; + uint32_t last_ticks; + uint32_t last_tick_offset; rtems_capture_control_t* control; struct rtems_capture_task_s* forw; struct rtems_capture_task_s* back; @@ -124,46 +180,64 @@ typedef struct rtems_capture_task_s typedef struct rtems_capture_record_s { rtems_capture_task_t* task; - uint32_t events; - uint32_t ticks; - uint32_t tick_offset; + uint32_t events; + uint32_t ticks; + uint32_t tick_offset; } rtems_capture_record_t; /** * The capture record event flags. */ -#define RTEMS_CAPTURE_REAL_PRI_EVENT_MASK UINT32_C(0x000000ff) -#define RTEMS_CAPTURE_CURR_PRI_EVENT_MASK UINT32_C(0x0000ff00) +#define RTEMS_CAPTURE_REAL_PRI_EVENT_MASK UINT32_C (0x000000ff) +#define RTEMS_CAPTURE_CURR_PRI_EVENT_MASK UINT32_C (0x0000ff00) #define RTEMS_CAPTURE_REAL_PRIORITY_EVENT (0) #define RTEMS_CAPTURE_CURR_PRIORITY_EVENT (8) #define RTEMS_CAPTURE_EVENT_START (16) -#define RTEMS_CAPTURE_CREATED_BY_EVENT UINT32_C(0x00010000) -#define RTEMS_CAPTURE_CREATED_EVENT UINT32_C(0x00020000) -#define RTEMS_CAPTURE_STARTED_BY_EVENT UINT32_C(0x00040000) -#define RTEMS_CAPTURE_STARTED_EVENT UINT32_C(0x00080000) -#define RTEMS_CAPTURE_RESTARTED_BY_EVENT UINT32_C(0x00100000) -#define RTEMS_CAPTURE_RESTARTED_EVENT UINT32_C(0x00200000) -#define RTEMS_CAPTURE_DELETED_BY_EVENT UINT32_C(0x00400000) -#define RTEMS_CAPTURE_DELETED_EVENT UINT32_C(0x00800000) -#define RTEMS_CAPTURE_BEGIN_EVENT UINT32_C(0x01000000) -#define RTEMS_CAPTURE_EXITTED_EVENT UINT32_C(0x02000000) -#define RTEMS_CAPTURE_SWITCHED_OUT_EVENT UINT32_C(0x04000000) -#define RTEMS_CAPTURE_SWITCHED_IN_EVENT UINT32_C(0x08000000) -#define RTEMS_CAPTURE_TIMESTAMP UINT32_C(0x10000000) +#define RTEMS_CAPTURE_CREATED_BY_EVENT UINT32_C (0x00010000) +#define RTEMS_CAPTURE_CREATED_EVENT UINT32_C (0x00020000) +#define RTEMS_CAPTURE_STARTED_BY_EVENT UINT32_C (0x00040000) +#define RTEMS_CAPTURE_STARTED_EVENT UINT32_C (0x00080000) +#define RTEMS_CAPTURE_RESTARTED_BY_EVENT UINT32_C (0x00100000) +#define RTEMS_CAPTURE_RESTARTED_EVENT UINT32_C (0x00200000) +#define RTEMS_CAPTURE_DELETED_BY_EVENT UINT32_C (0x00400000) +#define RTEMS_CAPTURE_DELETED_EVENT UINT32_C (0x00800000) +#define RTEMS_CAPTURE_BEGIN_EVENT UINT32_C (0x01000000) +#define RTEMS_CAPTURE_EXITTED_EVENT UINT32_C (0x02000000) +#define RTEMS_CAPTURE_SWITCHED_OUT_EVENT UINT32_C (0x04000000) +#define RTEMS_CAPTURE_SWITCHED_IN_EVENT UINT32_C (0x08000000) +#define RTEMS_CAPTURE_TIMESTAMP UINT32_C (0x10000000) #define RTEMS_CAPTURE_EVENT_END (28) /** - * rtems_capture_trigger_t + * rtems_capture_trigger_mode_t * * DESCRIPTION: * - * The types of triggers that exist. FIXME: add more here. + * The types of trigger modes that exist. */ -typedef enum rtems_capture_trigger_t +typedef enum rtems_capture_trigger_mode_e { rtems_capture_to_any, rtems_capture_from_any, rtems_capture_from_to +} rtems_capture_trigger_mode_t; + +/** + * rtems_capture_trigger_t + * + * DESCRIPTION: + * + * The types of triggers that exist. + */ +typedef enum rtems_capture_trigger_e +{ + rtems_capture_switch, + rtems_capture_create, + rtems_capture_start, + rtems_capture_restart, + rtems_capture_delete, + rtems_capture_begin, + rtems_capture_exitted } rtems_capture_trigger_t; /** @@ -177,32 +251,23 @@ typedef enum rtems_capture_trigger_t */ typedef void (*rtems_capture_timestamp) - (uint32_t * ticks, uint32_t * micro); + (uint32_t* ticks, uint32_t* micro); /** * rtems_capture_open * * DESCRIPTION: * - * This function initialises the realtime trace manager allocating the capture - * buffer. It is assumed we have a working heap at stage of initialisation. + * This function initialises the realtime trace manager allocating the + * capture buffer. It is assumed we have a working heap at stage of + * initialisation. * */ rtems_status_code -rtems_capture_open (uint32_t size, +rtems_capture_open (uint32_t size, rtems_capture_timestamp timestamp); /** - * rtems_capture_free_info_on_task_delete - * - * DESCRIPTION: - * - * If non-zero task informaion if freed when a task is deleted. - * - */ -extern int rtems_capture_free_info_on_task_delete; - -/** * rtems_capture_close * * DESCRIPTION: @@ -223,6 +288,18 @@ rtems_capture_close (); rtems_status_code rtems_capture_control (rtems_boolean enable); +/** + * rtems_capture_monitor + * + * DESCRIPTION: + * + * This function enable the monitor mode. When in the monitor mode + * the tasks are monitored but no data is saved. This can be used + * to profile the load on a system. + */ +rtems_status_code +rtems_capture_monitor (rtems_boolean enable); + /* * rtems_capture_flush * @@ -268,16 +345,18 @@ rtems_capture_watch_del (rtems_name name, rtems_id id); * disabled. */ rtems_status_code -rtems_capture_watch_ctrl (rtems_name name, rtems_id id, rtems_boolean enable); +rtems_capture_watch_ctrl (rtems_name name, + rtems_id id, + rtems_boolean enable); /** * rtems_capture_watch_global * * DESCRIPTION: * - * This function allows control of a global watch. The watch can be enabled or - * disabled. A global watch configures all tasks below the ceiling and above - * the floor to be traced. + * This function allows control of a global watch. The watch can + * be enabled or disabled. A global watch configures all tasks below + * the ceiling and above the floor to be traced. */ rtems_status_code rtems_capture_watch_global (rtems_boolean enable); @@ -343,14 +422,7 @@ rtems_capture_watch_get_floor (); * * DESCRIPTION: * - * This function sets an edge trigger. Left is the left side of - * the edge and right is right side of the edge. The trigger type - * can be - - * - * FROM_ANY : a switch from any task to the right side of the edge. - * TO_ANY : a switch from the left side of the edge to any task. - * FROM_TO : a switch from the left side of the edge to the right - * side of the edge. + * This function sets a trigger. * * This set trigger routine will create a trace control for the * target task. The task list is searched and any existing tasks @@ -361,11 +433,29 @@ rtems_capture_watch_get_floor (); * linked to single control. */ rtems_status_code -rtems_capture_set_trigger (rtems_name from, - rtems_id from_id, - rtems_name to, - rtems_id to_id, - rtems_capture_trigger_t trigger); +rtems_capture_set_trigger (rtems_name from_name, + rtems_id from_id, + rtems_name to_name, + rtems_id to_id, + rtems_capture_trigger_mode_t mode, + rtems_capture_trigger_t trigger); + +/** + * rtems_capture_clear_trigger + * + * DESCRIPTION: + * + * This function clears a trigger. + * + * This clear trigger routine will not clear a watch. + */ +rtems_status_code +rtems_capture_clear_trigger (rtems_name from_name, + rtems_id from_id, + rtems_name to_name, + rtems_id to_id, + rtems_capture_trigger_mode_t mode, + rtems_capture_trigger_t trigger); /** * rtems_capture_read @@ -394,14 +484,14 @@ rtems_capture_set_trigger (rtems_name from, * thrashing occuring for a small number of records, yet allows * a user configured latiency to be applied for single events. * - * The 'timeout' parameter is in micro-seconds. A value of 0 will disable - * the timeout. + * The 'timeout' parameter is in micro-seconds. A value of 0 will + * disable the timeout. * */ rtems_status_code -rtems_capture_read (uint32_t threshold, - uint32_t timeout, - uint32_t * read, +rtems_capture_read (uint32_t threshold, + uint32_t timeout, + uint32_t* read, rtems_capture_record_t** recs); /** @@ -413,7 +503,7 @@ rtems_capture_read (uint32_t threshold, * to the capture engine. The count must match the number read. */ rtems_status_code -rtems_capture_release (uint32_t count); +rtems_capture_release (uint32_t count); /** * rtems_capture_tick_time @@ -825,33 +915,101 @@ rtems_capture_control_flags (rtems_capture_control_t* control) } /** - * rtems_capture_control_from_name + * rtems_capture_control_to_triggers + * + * DESCRIPTION: + * + * This function returns the task control to triggers. + */ +static inline uint32_t +rtems_capture_control_to_triggers (rtems_capture_control_t* control) +{ + return control->to_triggers; +} + +/** + * rtems_capture_control_from_triggers * * DESCRIPTION: * - * This function returns the control from task name. + * This function returns the task control from triggers. + */ +static inline uint32_t +rtems_capture_control_from_triggers (rtems_capture_control_t* control) +{ + return control->from_triggers; +} + +/** + * rtems_capture_control_all_by_triggers + * + * DESCRIPTION: + * + * This function returns the task control by triggers. + */ +static inline uint32_t +rtems_capture_control_all_by_triggers (rtems_capture_control_t* control) +{ + return control->by_triggers; +} + +/** + * rtems_capture_control_by_valid + * + * DESCRIPTION: + * + * This function returns the control valid BY flags. + */ +static inline int +rtems_capture_control_by_valid (rtems_capture_control_t* control, int slot) +{ + return control->by_valid & RTEMS_CAPTURE_CONTROL_FROM_MASK (slot); +} + +/** + * rtems_capture_control_by_name + * + * DESCRIPTION: + * + * This function returns the control BY task name. */ static inline rtems_name -rtems_capture_control_from_name (rtems_capture_control_t* control, int from) +rtems_capture_control_by_name (rtems_capture_control_t* control, int by) { - if (from < RTEMS_CAPTURE_TRIGGER_TASKS) - return control->from[from]; - return control->from[0]; + if (by < RTEMS_CAPTURE_TRIGGER_TASKS) + return control->by[by].name; + return control->by[0].name; } /** - * rtems_capture_control_from_id + * rtems_capture_control_by_id * * DESCRIPTION: * - * This function returns the control from task id. + * This function returns the control BY task id. */ static inline rtems_id -rtems_capture_control_from_id (rtems_capture_control_t* control, int from) +rtems_capture_control_by_id (rtems_capture_control_t* control, int by) +{ + if (by < RTEMS_CAPTURE_TRIGGER_TASKS) + return control->by[by].id; + return control->by[0].id; +} + +/** + * rtems_capture_control_by_triggers + * + * DESCRIPTION: + * + * This function returns the control BY task triggers. + */ +static inline uint32_t +rtems_capture_control_by_triggers (rtems_capture_control_t* control, + int by) { - if (from < RTEMS_CAPTURE_TRIGGER_TASKS) - return control->from_id[from]; - return control->from_id[0]; + if (by < RTEMS_CAPTURE_TRIGGER_TASKS) + return control->by[by].trigger; + return control->by[0].trigger; } /** @@ -866,7 +1024,7 @@ static inline uint32_t rtems_capture_control_count () { rtems_capture_control_t* control = rtems_capture_get_control_list (); - uint32_t count = 0; + uint32_t count = 0; while (control) { |