source: rtems/cpukit/libmisc/capture/capture-cli.c @ 1374fd3

4.104.114.84.95
Last change on this file since 1374fd3 was 1374fd3, checked in by Chris Johns <chrisj@…>, on 08/17/07 at 00:54:16

2007-08-17 Chris Johns <chrisj@…>

  • 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.
  • Property mode set to 100644
File size: 39.5 KB
Line 
1/*
2  ------------------------------------------------------------------------
3  $Id$
4  ------------------------------------------------------------------------
5
6  Copyright Objective Design Systems Pty Ltd, 2002
7  All rights reserved Objective Design Systems Pty Ltd, 2002
8  Chris Johns (ccj@acm.org)
9
10  COPYRIGHT (c) 1989-1998.
11  On-Line Applications Research Corporation (OAR).
12
13  The license and distribution terms for this file may be
14  found in the file LICENSE in this distribution.
15
16  This software with is provided ``as is'' and with NO WARRANTY.
17
18  ------------------------------------------------------------------------
19
20  RTEMS Performance Monitoring and Measurement Framework.
21
22  This is the Target Interface Command Line Interface. You need
23  start the RTEMS monitor.
24
25*/
26
27#ifdef HAVE_CONFIG_H
28#include "config.h"
29#endif
30
31#include <ctype.h>
32#include <stdlib.h>
33#include <stdio.h>
34#include <string.h>
35#include <inttypes.h>
36
37#include <rtems.h>
38#include <rtems/capture-cli.h>
39#include <rtems/monitor.h>
40
41#define RTEMS_CAPTURE_CLI_MAX_LOAD_TASKS (20)
42
43/*
44 * The user capture timestamper.
45 */
46static rtems_capture_timestamp capture_timestamp;
47
48/*
49 * Common variable to sync the load monitor task.
50 */
51static volatile int cli_load_thread_active;
52
53/*
54 * rtems_capture_cli_open
55 *
56 *  DESCRIPTION:
57 *
58 * This function opens the capture engine. We need the size of the
59 * capture buffer.
60 *
61 */
62
63static const char* open_usage = "usage: copen [-i] size\n";
64
65static void
66rtems_capture_cli_open (int                          argc,
67                        char**                       argv,
68                        rtems_monitor_command_arg_t* command_arg,
69                        boolean                      verbose)
70{
71  uint32_t          size = 0;
72  rtems_boolean     enable = 0;
73  rtems_status_code sc;
74  int               arg;
75
76  if (argc <= 1)
77  {
78    fprintf (stdout, open_usage);
79    return;
80  }
81
82  for (arg = 1; arg < argc; arg++)
83  {
84    if (argv[arg][0] == '-')
85    {
86      if (argv[arg][1] == 'i')
87        enable = 1;
88      else
89        fprintf (stdout, "warning: option -%c ignored\n", argv[arg][1]);
90    }
91    else
92    {
93      size = strtoul (argv[arg], 0, 0);
94
95      if (size < 100)
96      {
97        fprintf (stdout, "error: size must be greater than or equal to 100\n");
98        return;
99      }
100    }
101  }
102
103  sc = rtems_capture_open (size, capture_timestamp);
104
105  if (sc != RTEMS_SUCCESSFUL)
106  {
107    fprintf (stdout, "error: open failed: %s\n", rtems_status_text (sc));
108    return;
109  }
110
111  fprintf (stdout, "capture engine opened.\n");
112
113  if (!enable)
114    return;
115
116  sc = rtems_capture_control (enable);
117
118  if (sc != RTEMS_SUCCESSFUL)
119  {
120    fprintf (stdout, "error: open enable failed: %s\n", rtems_status_text (sc));
121    return;
122  }
123
124  fprintf (stdout, "capture engine enabled.\n");
125}
126
127/*
128 * rtems_capture_cli_close
129 *
130 *  DESCRIPTION:
131 *
132 * This function closes the capture engine.
133 *
134 */
135
136static void
137rtems_capture_cli_close (int                          argc,
138                         char**                       argv,
139                         rtems_monitor_command_arg_t* command_arg,
140                         boolean                      verbose)
141{
142  rtems_status_code sc;
143
144  sc = rtems_capture_close ();
145
146  if (sc != RTEMS_SUCCESSFUL)
147  {
148    fprintf (stdout, "error: close failed: %s\n", rtems_status_text (sc));
149    return;
150  }
151
152  fprintf (stdout, "capture engine closed.\n");
153}
154
155/*
156 * rtems_capture_cli_enable
157 *
158 *  DESCRIPTION:
159 *
160 * This function enables the capture engine.
161 *
162 */
163
164static void
165rtems_capture_cli_enable (int                          argc,
166                          char**                       argv,
167                          rtems_monitor_command_arg_t* command_arg,
168                          boolean                      verbose)
169{
170  rtems_status_code sc;
171
172  sc = rtems_capture_control (1);
173
174  if (sc != RTEMS_SUCCESSFUL)
175  {
176    fprintf (stdout, "error: enable failed: %s\n", rtems_status_text (sc));
177    return;
178  }
179
180  fprintf (stdout, "capture engine enabled.\n");
181}
182
183/*
184 * rtems_capture_cli_disable
185 *
186 *  DESCRIPTION:
187 *
188 * This function disables the capture engine.
189 *
190 */
191
192static void
193rtems_capture_cli_disable (int                          argc,
194                           char**                       argv,
195                           rtems_monitor_command_arg_t* command_arg,
196                           boolean                      verbose)
197{
198  rtems_status_code sc;
199
200  sc = rtems_capture_control (0);
201
202  if (sc != RTEMS_SUCCESSFUL)
203  {
204    fprintf (stdout, "error: disable failed: %s\n", rtems_status_text (sc));
205    return;
206  }
207
208  fprintf (stdout, "capture engine disabled.\n");
209}
210
211/*
212 * rtems_capture_cli_task_list
213 *
214 *  DESCRIPTION:
215 *
216 * This function lists the tasks the capture engine knows about.
217 *
218 */
219
220static void
221rtems_capture_cli_task_list (int                          argc,
222                             char**                       argv,
223                             rtems_monitor_command_arg_t* command_arg,
224                             boolean                      verbose)
225{
226  rtems_task_priority   ceiling = rtems_capture_watch_get_ceiling ();
227  rtems_task_priority   floor = rtems_capture_watch_get_floor ();
228  rtems_capture_task_t* task = rtems_capture_get_task_list ();
229  uint32_t              ticks;
230  uint32_t              tick_offset;
231  unsigned long long    total_time;
232  int                   count = rtems_capture_task_count ();
233
234  if (capture_timestamp)
235    capture_timestamp (&ticks, &tick_offset);
236  else
237  {
238    ticks = _Watchdog_Ticks_since_boot;
239    tick_offset = 0;
240  }
241
242  fprintf (stdout, "total %i\n", count);
243
244  while (task)
245  {
246    rtems_task_priority priority;
247    int32_t             stack_used;
248    int32_t             time_used;
249
250    stack_used = rtems_capture_task_stack_usage (task);
251    if (stack_used)
252      stack_used = (stack_used * 100) / stack_used;
253
254    if (stack_used > 100)
255      stack_used = 100;
256
257    total_time = (ticks * rtems_capture_task_time (task)) + tick_offset;
258
259    time_used = (rtems_capture_task_time (task) * 100) / total_time;
260
261    if (time_used > 100)
262      time_used = 100;
263
264    priority = rtems_capture_task_real_priority (task);
265
266    fprintf (stdout, " ");
267    rtems_monitor_dump_id (rtems_capture_task_id (task));
268    fprintf (stdout, " ");
269    rtems_monitor_dump_name (rtems_capture_task_name (task));
270    fprintf (stdout, " ");
271    rtems_monitor_dump_priority (rtems_capture_task_start_priority (task));
272    fprintf (stdout, " ");
273    rtems_monitor_dump_priority (rtems_capture_task_real_priority (task));
274    fprintf (stdout, " ");
275    rtems_monitor_dump_priority (rtems_capture_task_curr_priority (task));
276    fprintf (stdout, " ");
277    rtems_monitor_dump_state (rtems_capture_task_state (task));
278    fprintf (stdout, " %c%c",
279             rtems_capture_task_valid (task) ? 'a' : 'd',
280             rtems_capture_task_flags (task) & RTEMS_CAPTURE_TRACED ? 't' : '-');
281
282    if ((floor > ceiling) && (ceiling > priority))
283      fprintf (stdout, "--");
284    else
285    {
286      uint32_t flags = rtems_capture_task_control_flags (task);
287      fprintf (stdout, "%c%c",
288               rtems_capture_task_control (task) ?
289               (flags & RTEMS_CAPTURE_WATCH ? 'w' : '+') : '-',
290               rtems_capture_watch_global_on () ? 'g' : '-');
291    }
292    fprintf (stdout, " %3" PRId32 "%% %3" PRId32 "%% (%" PRIu32 ")\n",
293            stack_used, time_used, rtems_capture_task_ticks (task));
294
295    task = rtems_capture_next_task (task);
296  }
297}
298
299/*
300 * rtems_capture_cli_task_load_thread
301 *
302 *  DESCRIPTION:
303 *
304 * This function displays the load of the tasks on an ANSI terminal.
305 *
306 */
307
308static void
309rtems_capture_cli_task_load_thread (rtems_task_argument arg)
310{
311  rtems_task_priority ceiling = rtems_capture_watch_get_ceiling ();
312  rtems_task_priority floor = rtems_capture_watch_get_floor ();
313  int                 last_count = 0;
314 
315  for (;;)
316  {
317    rtems_capture_task_t* tasks[RTEMS_CAPTURE_CLI_MAX_LOAD_TASKS + 1];
318    unsigned long long    load[RTEMS_CAPTURE_CLI_MAX_LOAD_TASKS + 1];
319    rtems_capture_task_t* task;
320    unsigned long long    total_time;
321    int                   count = 0;
322    int                   i;
323    int                   j;
324
325    cli_load_thread_active = 1;
326
327    /*
328     * Iterate over the tasks and sort the highest load tasks
329     * into our local arrays. We only handle a limited number of
330     * tasks.
331     */
332
333    memset (tasks, 0, sizeof (tasks));
334    memset (load, 0, sizeof (load));
335
336    task = rtems_capture_get_task_list ();
337
338    total_time = 0;
339
340    while (task)
341    {
342      if (rtems_capture_task_valid (task))
343      {
344        unsigned long long l = rtems_capture_task_delta_time (task);
345
346        count++;
347
348        total_time += l;
349
350        for (i = 0; i < RTEMS_CAPTURE_CLI_MAX_LOAD_TASKS; i++)
351        {
352          if (tasks[i])
353          {
354            if ((l == 0) || (l < load[i]))
355              continue;
356
357            for (j = (RTEMS_CAPTURE_CLI_MAX_LOAD_TASKS - 1); j >= i; j--)
358            {
359              tasks[j + 1] = tasks[j];
360              load[j + 1]  = load[j];
361            }
362          }
363
364          tasks[i] = task;
365          load[i]  = l;
366          break;
367        }
368      }
369      task = rtems_capture_next_task (task);
370    }
371
372    fprintf (stdout, "\x1b[H\x1b[J Press ENTER to exit.\n\n");
373    fprintf (stdout,
374             "     PID NAME RPRI CPRI STATE  %%CPU     %%STK FLGS    EXEC TIME\n");
375
376    if (count > last_count)
377      j = count;
378    else
379      j = last_count;
380
381    for (i = 0; i < RTEMS_CAPTURE_CLI_MAX_LOAD_TASKS; i++)
382    {
383      rtems_task_priority priority;
384      int                 stack_used;
385      int                 task_load;
386      int                 k;
387
388      if (!tasks[i])
389        break;
390
391      j--;
392
393      stack_used = rtems_capture_task_stack_usage (tasks[i]);
394      if (stack_used)
395        stack_used = (stack_used * 100) / stack_used;
396
397      if (stack_used > 100)
398        stack_used = 100;
399
400      task_load = (int) ((load[i] * 100000) / total_time);
401
402      priority = rtems_capture_task_real_priority (tasks[i]);
403
404      fprintf (stdout, "\x1b[K");
405      rtems_monitor_dump_id (rtems_capture_task_id (tasks[i]));
406      fprintf (stdout, " ");
407      rtems_monitor_dump_name (rtems_capture_task_name (tasks[i]));
408      fprintf (stdout, "  ");
409      rtems_monitor_dump_priority (priority);
410      fprintf (stdout, "  ");
411      rtems_monitor_dump_priority (rtems_capture_task_curr_priority (tasks[i]));
412      fprintf (stdout, " ");
413      k = rtems_monitor_dump_state (rtems_capture_task_state (tasks[i]));
414      fprintf (stdout, "%*c %3i.%03i%% ", 6 - k, ' ',
415               task_load / 1000, task_load % 1000);
416      fprintf (stdout, "%3i%% %c%c", stack_used,
417              rtems_capture_task_valid (tasks[i]) ? 'a' : 'd',
418              rtems_capture_task_flags (tasks[i]) & RTEMS_CAPTURE_TRACED ? 't' : '-');
419
420      if ((floor > ceiling) && (ceiling > priority))
421        fprintf (stdout, "--");
422      else
423        fprintf (stdout, "%c%c",
424                rtems_capture_task_control (tasks[i]) ?
425                (rtems_capture_task_control_flags (tasks[i]) &
426                 RTEMS_CAPTURE_WATCH ? 'w' : '+') : '-',
427                rtems_capture_watch_global_on () ? 'g' : '-');
428
429      fprintf (stdout, "   %qi\n", rtems_capture_task_time (tasks[i]));
430    }
431
432    if (count < RTEMS_CAPTURE_CLI_MAX_LOAD_TASKS)
433    {
434      j = RTEMS_CAPTURE_CLI_MAX_LOAD_TASKS - count;   
435      while (j > 0)
436      {
437        fprintf (stdout, "\x1b[K\n");
438        j--;
439      }
440    }
441   
442    last_count = count;
443
444    cli_load_thread_active = 0;
445
446    rtems_task_wake_after (TOD_MICROSECONDS_TO_TICKS (5000000));
447  }
448}
449
450/*
451 * rtems_capture_cli_task_load
452 *
453 *  DESCRIPTION:
454 *
455 * This function is a monitor command.
456 *
457 */
458
459static void
460rtems_capture_cli_task_load (int                          argc,
461                             char**                       argv,
462                             rtems_monitor_command_arg_t* command_arg,
463                             boolean                      verbose)
464{
465  rtems_status_code   sc;
466  rtems_task_priority priority;
467  rtems_name          name;
468  rtems_id            id;
469
470  sc = rtems_task_set_priority (RTEMS_SELF, RTEMS_CURRENT_PRIORITY, &priority);
471
472  if (sc != RTEMS_SUCCESSFUL)
473  {
474    fprintf (stdout, "error: cannot obtain the current priority: %s\n",
475             rtems_status_text (sc));
476    return;
477  }
478
479  name = rtems_build_name('C', 'P', 'l', 't');
480 
481  sc = rtems_task_create (name, priority, 4 * 1024,
482                          RTEMS_NO_FLOATING_POINT | RTEMS_LOCAL,
483                          RTEMS_PREEMPT | RTEMS_TIMESLICE | RTEMS_NO_ASR,
484                          &id);
485 
486  if (sc != RTEMS_SUCCESSFUL)
487  {
488    fprintf (stdout, "error: cannot create helper thread: %s\n",
489             rtems_status_text (sc));
490    return;
491  }
492
493  sc = rtems_task_start (id, rtems_capture_cli_task_load_thread, 0);
494
495  if (sc != RTEMS_SUCCESSFUL)
496  {
497    fprintf (stdout, "error: cannot start helper thread: %s\n",
498             rtems_status_text (sc));
499    rtems_task_delete (id);
500    return;
501  }
502
503  for (;;)
504  {
505    int c = getchar ();
506
507    if ((c == '\r') || (c == '\n'))
508    {
509      int loops = 20;
510
511      while (loops && cli_load_thread_active)
512        rtems_task_wake_after (TOD_MICROSECONDS_TO_TICKS (100000));
513
514      rtems_task_delete (id);
515
516      fprintf (stdout, "load monitoring stopped.\n");
517
518      return;
519    }
520  }
521}
522
523/*
524 * rtems_capture_cli_watch_list
525 *
526 *  DESCRIPTION:
527 *
528 * This function lists the controls in the capture engine.
529 *
530 */
531
532static void
533rtems_capture_cli_watch_list (int                          argc,
534                              char**                       argv,
535                              rtems_monitor_command_arg_t* command_arg,
536                              boolean                      verbose)
537{
538  rtems_capture_control_t* control = rtems_capture_get_control_list ();
539  rtems_task_priority      ceiling = rtems_capture_watch_get_ceiling ();
540  rtems_task_priority      floor = rtems_capture_watch_get_floor ();
541
542  fprintf (stdout, "watch priority ceiling is %" PRId32 "\n", ceiling);
543  fprintf (stdout, "watch priority floor is %" PRId32 "\n", floor);
544  fprintf (stdout, "global watch is %s\n",
545          rtems_capture_watch_global_on () ? "enabled" : "disabled");
546  fprintf (stdout, "total %" PRId32 "\n", rtems_capture_control_count ());
547
548  while (control)
549  {
550    uint32_t flags;
551    int      f;
552    int      fshowed;
553    int      lf;
554
555    fprintf (stdout, " ");
556    rtems_monitor_dump_id (rtems_capture_control_id (control));
557    fprintf (stdout, " ");
558    rtems_monitor_dump_name (rtems_capture_control_name (control));
559    flags = rtems_capture_control_flags (control);
560    fprintf (stdout, " %c%c ",
561             rtems_capture_watch_global_on () ? 'g' : '-',
562             flags & RTEMS_CAPTURE_WATCH ? 'w' : '-');
563    flags = rtems_capture_control_to_triggers (control);
564    fprintf (stdout, " T:%c%c%c%c%c%c%c",
565             flags & RTEMS_CAPTURE_SWITCH    ? 'S' : '-',
566             flags & RTEMS_CAPTURE_CREATE ? 'C' : '-',
567             flags & RTEMS_CAPTURE_START ? 'S' : '-',
568             flags & RTEMS_CAPTURE_RESTART ? 'R' : '-',
569             flags & RTEMS_CAPTURE_DELETE ? 'D' : '-',
570             flags & RTEMS_CAPTURE_BEGIN ? 'B' : '-',
571             flags & RTEMS_CAPTURE_EXITTED ? 'E' : '-');
572    flags = rtems_capture_control_from_triggers (control);
573    fprintf (stdout, " F:%c%c%c%c%c",
574             flags & RTEMS_CAPTURE_SWITCH  ? 'S' : '-',
575             flags & RTEMS_CAPTURE_CREATE  ? 'C' : '-',
576             flags & RTEMS_CAPTURE_START   ? 'S' : '-',
577             flags & RTEMS_CAPTURE_RESTART ? 'R' : '-',
578             flags & RTEMS_CAPTURE_DELETE  ? 'D' : '-');
579
580    for (f = 0, fshowed = 0, lf = 1; f < RTEMS_CAPTURE_TRIGGER_TASKS; f++)
581    {
582      if (rtems_capture_control_by_valid (control, f))
583      {
584        if (lf && ((fshowed % 3) == 0))
585        {
586          fprintf (stdout, "\n");
587          lf = 0;
588        }
589
590        fprintf (stdout, "  %2i:", f);
591        rtems_monitor_dump_name (rtems_capture_control_by_name (control, f));
592        fprintf (stdout, "/");
593        rtems_monitor_dump_id (rtems_capture_control_by_id (control, f));
594        flags = rtems_capture_control_by_triggers (control, f);
595        fprintf (stdout, ":%c%c%c%c%c",
596                 flags & RTEMS_CAPTURE_SWITCH  ? 'S' : '-',
597                 flags & RTEMS_CAPTURE_CREATE  ? 'C' : '-',
598                 flags & RTEMS_CAPTURE_START   ? 'S' : '-',
599                 flags & RTEMS_CAPTURE_RESTART ? 'R' : '-',
600                 flags & RTEMS_CAPTURE_DELETE  ? 'D' : '-');
601        fshowed++;
602        lf = 1;
603      }
604    }
605
606    if (lf)
607      fprintf (stdout, "\n");
608
609    control = rtems_capture_next_control (control);
610  }
611}
612
613/*
614 * rtems_capture_cli_get_name_id
615 *
616 *  DESCRIPTION:
617 *
618 * This function checks arguments for a name or an id.
619 *
620 */
621
622static rtems_boolean
623rtems_capture_cli_get_name_id (char*          arg,
624                               rtems_boolean* valid_name,
625                               rtems_boolean* valid_id,
626                               rtems_name*    name,
627                               rtems_id*      id)
628{
629  size_t l;
630  size_t i;
631
632  if (*valid_name && *valid_id)
633  {
634    fprintf (stdout, "error: too many arguments\n");
635    return 0;
636  }
637
638  /*
639   * See if the arg is all hex digits.
640   */
641
642  l = strlen (arg);
643
644  for (i = 0; i < l; i++)
645    if (!isxdigit (arg[i]))
646      break;
647
648  if (i == l)
649  {
650    *id = strtoul (arg, 0, 16);
651    *valid_id = 1;
652  }
653  else
654  {
655    /*
656     * This is a bit of hack but it should work on all platforms
657     * as it is what the score does with names.
658     *
659     * @warning The extra assigns play with the byte order so do not
660     *          remove unless the score has been updated.
661     */
662    Objects_Name object_name;
663    rtems_name   rname;
664   
665    rname = rtems_build_name(arg[0], arg[1], arg[2], arg[3]);
666    object_name = (Objects_Name) rname;
667    *name = (rtems_name) object_name;
668    *valid_name = 1;
669  }
670
671  return 1;
672}
673
674/*
675 * rtems_capture_cli_watch_add
676 *
677 *  DESCRIPTION:
678 *
679 * This function is a monitor command that add a watch to the capture
680 * engine.
681 *
682 */
683
684static char const * watch_add_usage = "usage: cwadd [task name] [id]\n";
685
686static void
687rtems_capture_cli_watch_add (int                          argc,
688                             char**                       argv,
689                             rtems_monitor_command_arg_t* command_arg,
690                             boolean                      verbose)
691{
692  rtems_status_code sc;
693  int               arg;
694  rtems_name        name = 0;
695  rtems_id          id = 0;
696  rtems_boolean     valid_name = 0;
697  rtems_boolean     valid_id = 0;
698
699  if (argc <= 1)
700  {
701    fprintf (stdout, watch_add_usage);
702    return;
703  }
704
705  for (arg = 1; arg < argc; arg++)
706  {
707    if (argv[arg][0] == '-')
708    {
709      fprintf (stdout, "warning: option -%c ignored\n", argv[arg][1]);
710    }
711    else
712    {
713      if (!rtems_capture_cli_get_name_id (argv[arg], &valid_name, &valid_id,
714                                          &name, &id))
715        return;
716    }
717  }
718
719  if (!valid_name && !valid_id)
720  {
721    fprintf (stdout, "error: no valid name or task id located\n");
722    return;
723  }
724
725  sc = rtems_capture_watch_add (name, id);
726
727  if (sc != RTEMS_SUCCESSFUL)
728  {
729    fprintf (stdout,
730             "error: watch add failed: %s\n", rtems_status_text (sc));
731    return;
732  }
733
734  fprintf (stdout, "watch added.\n");
735}
736
737/*
738 * rtems_capture_cli_watch_del
739 *
740 *  DESCRIPTION:
741 *
742 * This function is a monitor command that deletes a watch from the capture
743 * engine.
744 *
745 */
746
747static char const * watch_del_usage = "usage: cwdel [task name] [id]\n";
748
749static void
750rtems_capture_cli_watch_del (int                          argc,
751                             char**                       argv,
752                             rtems_monitor_command_arg_t* command_arg,
753                             boolean                      verbose)
754{
755  rtems_status_code sc;
756  int               arg;
757  rtems_name        name = 0;
758  rtems_id          id = 0;
759  rtems_boolean     valid_name = 0;
760  rtems_boolean     valid_id = 0;
761
762  if (argc <= 1)
763  {
764    fprintf (stdout, watch_del_usage);
765    return;
766  }
767
768  for (arg = 1; arg < argc; arg++)
769  {
770    if (argv[arg][0] == '-')
771    {
772      fprintf (stdout, "warning: option -%c ignored\n", argv[arg][1]);
773    }
774    else
775    {
776      if (!rtems_capture_cli_get_name_id (argv[arg], &valid_name, &valid_id,
777                                          &name, &id))
778        return;
779    }
780  }
781
782  if (!valid_name && !valid_id)
783  {
784    fprintf (stdout, "error: no valid name or task id located\n");
785    return;
786  }
787
788  sc = rtems_capture_watch_del (name, id);
789
790  if (sc != RTEMS_SUCCESSFUL)
791  {
792    fprintf (stdout, "error: watch delete failed: %s\n",
793             rtems_status_text (sc));
794    return;
795  }
796
797  fprintf (stdout, "watch delete.\n");
798}
799
800/*
801 * rtems_capture_cli_watch_control
802 *
803 *  DESCRIPTION:
804 *
805 * This function is a monitor command that controls a watch.
806 *
807 */
808
809static char const * watch_control_usage = "usage: cwctl [task name] [id] on/off\n";
810
811static void
812rtems_capture_cli_watch_control (int                          argc,
813                                 char**                       argv,
814                                 rtems_monitor_command_arg_t* command_arg,
815                                 boolean                      verbose)
816{
817  rtems_status_code sc;
818  int               arg;
819  rtems_name        name = 0;
820  rtems_id          id = 0;
821  rtems_boolean     valid_name = 0;
822  rtems_boolean     valid_id = 0;
823  rtems_boolean     enable = 0;
824
825  if (argc <= 2)
826  {
827    fprintf (stdout, watch_control_usage);
828    return;
829  }
830
831  for (arg = 1; arg < argc; arg++)
832  {
833    if (argv[arg][0] == '-')
834    {
835      fprintf (stdout, "warning: option -%c ignored\n", argv[arg][1]);
836    }
837    else
838    {
839      if (strcmp (argv[arg], "on") == 0)
840        enable = 1;
841      else if (strcmp (argv[arg], "off") == 0)
842        enable = 0;
843      else if (!rtems_capture_cli_get_name_id (argv[arg], &valid_name,
844                                               &valid_id, &name, &id))
845        return;
846    }
847  }
848
849  if (!valid_name && !valid_id)
850  {
851    fprintf (stdout, "error: no valid name or task id located\n");
852    return;
853  }
854
855  sc = rtems_capture_watch_ctrl (name, id, enable);
856
857  if (sc != RTEMS_SUCCESSFUL)
858  {
859    fprintf (stdout, "error: watch control failed: %s\n",
860             rtems_status_text (sc));
861    return;
862  }
863
864  fprintf (stdout, "watch %s.\n", enable ? "enabled" : "disabled");
865}
866
867/*
868 * rtems_capture_cli_watch_global
869 *
870 *  DESCRIPTION:
871 *
872 * This function is a monitor command that sets a global watch.
873 *
874 */
875
876static char const * watch_global_usage = "usage: cwglob on/off\n";
877
878static void
879rtems_capture_cli_watch_global (int                          argc,
880                                char**                       argv,
881                                rtems_monitor_command_arg_t* command_arg,
882                                boolean                      verbose)
883{
884  rtems_status_code sc;
885  int               arg;
886  rtems_boolean     enable = 0;
887
888  if (argc <= 1)
889  {
890    fprintf (stdout, watch_global_usage);
891    return;
892  }
893
894  for (arg = 1; arg < argc; arg++)
895  {
896    if (argv[arg][0] == '-')
897    {
898      fprintf (stdout, "warning: option -%c ignored\n", argv[arg][1]);
899    }
900    else
901    {
902      if (strcmp (argv[arg], "on") == 0)
903        enable = 1;
904      else if (strcmp (argv[arg], "off") == 0)
905        enable = 0;
906    }
907  }
908
909  sc = rtems_capture_watch_global (enable);
910
911  if (sc != RTEMS_SUCCESSFUL)
912  {
913    fprintf (stdout, "error: global watch failed: %s\n",
914             rtems_status_text (sc));
915    return;
916  }
917
918  fprintf (stdout, "global watch %s.\n", enable ? "enabled" : "disabled");
919}
920
921/*
922 * rtems_capture_cli_watch_ceiling
923 *
924 *  DESCRIPTION:
925 *
926 * This function is a monitor command that sets watch ceiling.
927 *
928 */
929
930static char const * watch_ceiling_usage = "usage: cwceil priority\n";
931
932static void
933rtems_capture_cli_watch_ceiling (int                          argc,
934                                 char**                       argv,
935                                 rtems_monitor_command_arg_t* command_arg,
936                                 boolean                      verbose)
937{
938  rtems_status_code   sc;
939  int                 arg;
940  rtems_task_priority priority = 0;
941
942  if (argc <= 1)
943  {
944    fprintf (stdout, watch_ceiling_usage);
945    return;
946  }
947
948  for (arg = 1; arg < argc; arg++)
949  {
950    if (argv[arg][0] == '-')
951    {
952      fprintf (stdout, "warning: option -%c ignored\n", argv[arg][1]);
953    }
954    else
955    {
956      priority = strtoul (argv[arg], 0, 0);
957    }
958  }
959
960  sc = rtems_capture_watch_ceiling (priority);
961
962  if (sc != RTEMS_SUCCESSFUL)
963  {
964    fprintf (stdout, "error: watch ceiling failed: %s\n",
965             rtems_status_text (sc));
966    return;
967  }
968
969  fprintf (stdout, "watch ceiling is %" PRId32 ".\n", priority);
970}
971
972/*
973 * rtems_capture_cli_watch_floor
974 *
975 *  DESCRIPTION:
976 *
977 * This function is a monitor command that sets watch floor.
978 *
979 */
980
981static char const * watch_floor_usage = "usage: cwfloor priority\n";
982
983static void
984rtems_capture_cli_watch_floor (int                          argc,
985                               char**                       argv,
986                               rtems_monitor_command_arg_t* command_arg,
987                               boolean                      verbose)
988{
989  rtems_status_code   sc;
990  int                 arg;
991  rtems_task_priority priority = 0;
992
993  if (argc <= 1)
994  {
995    fprintf (stdout, watch_floor_usage);
996    return;
997  }
998
999  for (arg = 1; arg < argc; arg++)
1000  {
1001    if (argv[arg][0] == '-')
1002    {
1003      fprintf (stdout, "warning: option -%c ignored\n", argv[arg][1]);
1004    }
1005    else
1006    {
1007      priority = strtoul (argv[arg], 0, 0);
1008    }
1009  }
1010
1011  sc = rtems_capture_watch_floor (priority);
1012
1013  if (sc != RTEMS_SUCCESSFUL)
1014  {
1015    fprintf (stdout, "error: watch floor failed: %s\n",
1016             rtems_status_text (sc));
1017    return;
1018  }
1019
1020  fprintf (stdout, "watch floor is %" PRId32 ".\n", priority);
1021}
1022
1023/*
1024 * rtems_capture_cli_trigger_worker
1025 *
1026 *  DESCRIPTION:
1027 *
1028 * This function is a monitor command that sets or clears a trigger.
1029 *
1030 */
1031
1032static char const *trigger_set_usage =
1033      "usage: %s [-?] type [to name/id] [from] [from name/id]\n";
1034
1035static char const *trigger_set_types =
1036      "  You can say 'type TASK' or 'type TO from FROM'\n" \
1037      "  where TASK is the task the event is happening to\n" \
1038      "  or you can say the event TO this task FROM this task.\n" \
1039      "  No type defaults to 'switch'.\n" \
1040      "   switch  : context switch TASK or FROM or FROM->TO\n" \
1041      "   create  : create TASK, or create TO from FROM\n" \
1042      "   start   : start TASK, or start TO from FROM\n" \
1043      "   restart : restart TASK, or restart TO from FROM\n" \
1044      "   delete  : delete TASK or delete TO from FROM\n" \
1045      "   begin   : begin TASK\n" \
1046      "   exitted : exitted TASK\n";
1047
1048/*
1049 * Structure to handle the parsing of the trigger command line.
1050 */
1051typedef struct rtems_capture_cli_triggers_s
1052{
1053  char const *            name;
1054  rtems_capture_trigger_t type;
1055  int                     to_only;
1056} rtems_capture_cli_triggers_t;
1057
1058static rtems_capture_cli_triggers_t rtems_capture_cli_triggers[] =
1059{
1060  { "switch",  rtems_capture_switch,  0 }, /* must be first */
1061  { "create",  rtems_capture_create,  0 },
1062  { "start",   rtems_capture_start,   0 },
1063  { "restart", rtems_capture_restart, 0 },
1064  { "delete",  rtems_capture_delete,  0 },
1065  { "begin",   rtems_capture_begin,   1 },
1066  { "exitted", rtems_capture_exitted, 1 }
1067};
1068
1069typedef enum rtems_capture_cli_trig_state_e
1070{
1071  trig_type,
1072  trig_to,
1073  trig_from_from,
1074  trig_from
1075} rtems_capture_cli_trig_state_t;
1076
1077#define RTEMS_CAPTURE_CLI_TRIGGERS_NUM \
1078  (sizeof (rtems_capture_cli_triggers) / sizeof (rtems_capture_cli_triggers_t))
1079
1080static void
1081rtems_capture_cli_trigger_worker (int set, int argc, char** argv)
1082{
1083  rtems_status_code            sc;
1084  int                          arg;
1085  int                          trigger = 0; /* switch */
1086  rtems_capture_trigger_mode_t trigger_mode = rtems_capture_from_any;
1087  rtems_boolean                trigger_set = 0;
1088  rtems_boolean                is_from = 0;
1089  rtems_name                   name = 0;
1090  rtems_id                     id = 0;
1091  rtems_boolean                valid_name = 0;
1092  rtems_boolean                valid_id = 0;
1093  rtems_name                   from_name = 0;
1094  rtems_id                     from_id = 0;
1095  rtems_boolean                from_valid_name = 0;
1096  rtems_boolean                from_valid_id = 0;
1097  rtems_name                   to_name = 0;
1098  rtems_id                     to_id = 0;
1099  rtems_boolean                to_valid_name = 0;
1100  rtems_boolean                to_valid_id = 0;
1101
1102  for (arg = 1; arg < argc; arg++)
1103  {
1104    if (argv[arg][0] == '-')
1105    {
1106      switch (argv[arg][1])
1107      {
1108        case '?':
1109          fprintf (stdout, trigger_set_usage, set ? "ctset" : "ctclear");
1110          fprintf (stdout, trigger_set_types);
1111          return;
1112        default:
1113          fprintf (stdout, "warning: option -%c ignored\n", argv[arg][1]);
1114          break;
1115      }
1116    }
1117    else
1118    {
1119      if (!trigger_set)
1120      {
1121        rtems_boolean found = 0;
1122        int           t;
1123       
1124        for (t = 0; t < RTEMS_CAPTURE_CLI_TRIGGERS_NUM; t++)
1125          if (strcmp (argv[arg], rtems_capture_cli_triggers[t].name) == 0)
1126          {
1127            trigger = t;
1128            found = 1;
1129            break;
1130          }
1131
1132        trigger_set = 1;
1133
1134        /*
1135         * If a trigger was not found assume the default and
1136         * assume the parameter is a task name or id.
1137         */
1138        if (found)
1139          continue;
1140      }
1141
1142      if (strcmp (arg[argv], "from") == 0)
1143      {
1144        if (is_from)
1145          fprintf (stdout, "warning: extra 'from' ignored\n");
1146       
1147        is_from = 1;
1148        continue;
1149      }
1150
1151      if (!rtems_capture_cli_get_name_id (argv[arg], &valid_name, &valid_id,
1152                                          &name, &id))
1153        return;
1154
1155      if (valid_name)
1156      {
1157        if (is_from)
1158        {
1159          if (!from_valid_name && !from_valid_id)
1160          {
1161            from_valid_name = 1;
1162            from_name       = name;
1163          }
1164          else
1165            fprintf (stdout, "warning: extra arguments ignored\n");
1166        }
1167        else if (!to_valid_name && !to_valid_id)
1168        {
1169          to_valid_name = 1;
1170          to_name       = name;
1171        }
1172        else
1173          fprintf (stdout, "warning: extra arguments ignored\n");
1174      }
1175         
1176      if (valid_id)
1177      {
1178        if (is_from)
1179        {
1180          if (!from_valid_name && !from_valid_id)
1181          {
1182            from_valid_id = 1;
1183            from_id       = id;
1184          }
1185          else
1186            fprintf (stdout, "warning: extra arguments ignored\n");
1187        }
1188        else if (!to_valid_name && !to_valid_id)
1189        {
1190          to_valid_id = 1;
1191          to_id       = id;
1192        }
1193        else
1194          fprintf (stdout, "warning: extra arguments ignored\n");
1195      }
1196    }
1197  }
1198
1199  if (is_from && rtems_capture_cli_triggers[trigger].to_only)
1200  {
1201    fprintf (stdout, "error: a %s trigger can be a TO trigger\n",
1202             rtems_capture_cli_triggers[trigger].name);
1203    return;
1204  }
1205 
1206  if (!to_valid_name && !to_valid_id && !from_valid_name && !from_valid_id)
1207  {
1208    fprintf (stdout, trigger_set_usage);
1209    return;
1210  }
1211
1212  if (!is_from && !to_valid_name && !to_valid_id)
1213  {
1214    fprintf (stdout, "error: a %s trigger needs a TO name or id\n",
1215             rtems_capture_cli_triggers[trigger].name);
1216    return;
1217  }
1218
1219  if (is_from && !from_valid_name && !from_valid_id)
1220  {
1221    fprintf (stdout, "error: a %s trigger needs a FROM name or id\n",
1222             rtems_capture_cli_triggers[trigger].name);
1223    return;
1224  }
1225
1226  if ((from_valid_name || from_valid_id) && (to_valid_name || to_valid_id))
1227    trigger_mode = rtems_capture_from_to;
1228  else if (from_valid_name || from_valid_id)
1229    trigger_mode = rtems_capture_to_any;
1230  else if (to_valid_name || to_valid_id)
1231    trigger_mode = rtems_capture_from_any;
1232
1233  if (set)
1234    sc = rtems_capture_set_trigger (from_name, from_id, to_name, to_id,
1235                                    trigger_mode,
1236                                    rtems_capture_cli_triggers[trigger].type);
1237  else
1238    sc = rtems_capture_clear_trigger (from_name, from_id, to_name, to_id,
1239                                      trigger_mode,
1240                                      rtems_capture_cli_triggers[trigger].type);
1241
1242  if (sc != RTEMS_SUCCESSFUL)
1243  {
1244    fprintf (stdout, "error: %sing the trigger failed: %s\n",
1245             set ? "sett" : "clear", rtems_status_text (sc));
1246    return;
1247  }
1248
1249  fprintf (stdout, "trigger %s.\n", set ? "set" : "cleared");
1250}
1251
1252/*
1253 * rtems_capture_cli_trigger_set
1254 *
1255 *  DESCRIPTION:
1256 *
1257 * This function is a monitor command that sets a trigger.
1258 *
1259 */
1260
1261static void
1262rtems_capture_cli_trigger_set (int                          argc,
1263                               char**                       argv,
1264                               rtems_monitor_command_arg_t* command_arg,
1265                               boolean                      verbose)
1266{
1267  rtems_capture_cli_trigger_worker (1, argc, argv);
1268}
1269
1270/*
1271 * rtems_capture_cli_trigger_clear
1272 *
1273 *  DESCRIPTION:
1274 *
1275 * This function is a monitor command that clears a trigger.
1276 *
1277 */
1278
1279static void
1280rtems_capture_cli_trigger_clear (int                          argc,
1281                                 char**                       argv,
1282                                 rtems_monitor_command_arg_t* command_arg,
1283                                 boolean                      verbose)
1284{
1285  rtems_capture_cli_trigger_worker (0, argc, argv);
1286}
1287
1288/*
1289 * rtems_capture_cli_trace_records
1290 *
1291 *  DESCRIPTION:
1292 *
1293 * This function is a monitor command that dumps trace records.
1294 *
1295 */
1296
1297static void
1298rtems_capture_cli_trace_records (int                          argc,
1299                                 char**                       argv,
1300                                 rtems_monitor_command_arg_t* command_arg,
1301                                 boolean                      verbose)
1302{
1303  rtems_status_code       sc;
1304  rtems_boolean           csv = 0;
1305  static int              dump_total = 22;
1306  int                     total;
1307  int                     count;
1308  uint32_t                read;
1309  rtems_capture_record_t* rec;
1310  int                     arg;
1311
1312  for (arg = 1; arg < argc; arg++)
1313  {
1314    if (argv[arg][0] == '-')
1315    {
1316      if (argv[arg][1] == 'c')
1317        csv = 1;
1318      else
1319        fprintf (stdout, "warning: option -%c ignored\n", argv[arg][1]);
1320    }
1321    else
1322    {
1323      int i;
1324      int l;
1325
1326      l = strlen (argv[arg]);
1327
1328      for (i = 0; i < l; i++)
1329        if (!isdigit (argv[arg][i]))
1330        {
1331          fprintf (stdout, "error: not a number\n");
1332          return;
1333        }
1334
1335      dump_total = strtoul (argv[arg], 0, 0);
1336    }
1337  }
1338
1339  total = dump_total;
1340
1341  while (total)
1342  {
1343    sc = rtems_capture_read (0, 0, &read, &rec);
1344
1345    if (sc != RTEMS_SUCCESSFUL)
1346    {
1347      fprintf (stdout, "error: trace read failed: %s\n", rtems_status_text (sc));
1348      rtems_capture_flush (0);
1349      return;
1350    }
1351
1352    /*
1353     * If we have no records then just exist. We still need to release
1354     * the reader lock.
1355     */
1356   
1357    if (read == 0)
1358    {
1359      rtems_capture_release (read);
1360      break;
1361    }
1362
1363    count = total < read ? total : read;
1364   
1365    while (count--)
1366    {
1367      if (csv)
1368        fprintf (stdout, "%08" PRIx32 ",%03" PRIu32
1369                   ",%03" PRIu32 ",%04" PRIx32 ",%" PRId32 ",%" PRId32 "\n",
1370                (uint32_t) rec->task,
1371                (rec->events >> RTEMS_CAPTURE_REAL_PRIORITY_EVENT) & 0xff,
1372                (rec->events >> RTEMS_CAPTURE_CURR_PRIORITY_EVENT) & 0xff,
1373                (rec->events >> RTEMS_CAPTURE_EVENT_START),
1374                rec->ticks, rec->tick_offset);
1375      else
1376      {
1377        unsigned long long t;
1378        uint32_t     event;
1379        int                e;
1380
1381        event = rec->events >> RTEMS_CAPTURE_EVENT_START;
1382
1383        t  = rec->ticks;
1384        t *= rtems_capture_tick_time ();
1385        t += rec->tick_offset;
1386
1387        for (e = RTEMS_CAPTURE_EVENT_START; e < RTEMS_CAPTURE_EVENT_END; e++)
1388        {
1389          if (event & 1)
1390          {
1391            fprintf (stdout, "%9li.%06li ", (unsigned long) (t / 1000000),
1392                    (unsigned long) (t % 1000000));
1393            rtems_monitor_dump_id (rtems_capture_task_id (rec->task));
1394            fprintf (stdout, " ");
1395            rtems_monitor_dump_name (rtems_capture_task_name (rec->task));
1396            fprintf (stdout, " %3" PRId32 " %3" PRId32 " %s\n",
1397                    (rec->events >> RTEMS_CAPTURE_REAL_PRIORITY_EVENT) & 0xff,
1398                    (rec->events >> RTEMS_CAPTURE_CURR_PRIORITY_EVENT) & 0xff,
1399                    rtems_capture_event_text (e));
1400          }
1401          event >>= 1;
1402        }
1403      }
1404      rec++;
1405    }
1406
1407    count = total < read ? total : read;
1408   
1409    if (count < total)
1410      total -= count;
1411    else
1412      total = 0;
1413
1414    rtems_capture_release (count);
1415  }
1416}
1417
1418/*
1419 * rtems_capture_cli_flush
1420 *
1421 *  DESCRIPTION:
1422 *
1423 * This function is a monitor command that flushes and primes the capture
1424 * engine.
1425 *
1426 */
1427
1428static void
1429rtems_capture_cli_flush (int                          argc,
1430                         char**                       argv,
1431                         rtems_monitor_command_arg_t* command_arg,
1432                         boolean                      verbose)
1433{
1434  rtems_status_code sc;
1435  rtems_boolean     prime = 1;
1436  int               arg;
1437
1438  for (arg = 1; arg < argc; arg++)
1439  {
1440    if (argv[arg][0] == '-')
1441    {
1442      if (argv[arg][1] == 'n')
1443        prime = 0;
1444      else
1445        fprintf (stdout, "warning: option -%c ignored\n", argv[arg][1]);
1446    }
1447  }
1448
1449  sc = rtems_capture_flush (prime);
1450
1451  if (sc != RTEMS_SUCCESSFUL)
1452  {
1453    fprintf (stdout, "error: flush failed: %s\n", rtems_status_text (sc));
1454    return;
1455  }
1456
1457  fprintf (stdout, "trace buffer flushed and %s.\n",
1458           prime ? "primed" : "not primed");
1459}
1460
1461static rtems_monitor_command_entry_t rtems_capture_cli_cmds[] =
1462{
1463  {
1464    "copen",
1465    "usage: copen [-i] size\n",
1466    0,
1467    rtems_capture_cli_open,
1468    { 0 },
1469    0
1470  },
1471  {
1472    "cclose",
1473    "usage: cclose\n",
1474    0,
1475    rtems_capture_cli_close,
1476    { 0 },
1477    0
1478  },
1479  {
1480    "cenable",
1481    "usage: cenable\n",
1482    0,
1483    rtems_capture_cli_enable,
1484    { 0 },
1485    0
1486  },
1487  {
1488    "cdisable",
1489    "usage: cdisable\n",
1490    0,
1491    rtems_capture_cli_disable,
1492    { 0 },
1493    0
1494  },
1495  {
1496    "ctlist",
1497    "usage: ctlist \n",
1498    0,
1499     rtems_capture_cli_task_list,
1500    { 0 },
1501    0
1502  },
1503  {
1504    "ctload",
1505    "usage: ctload \n",
1506    0,
1507    rtems_capture_cli_task_load,
1508    { 0 },
1509    0
1510  },
1511  {
1512    "cwlist",
1513    "usage: cwlist\n",
1514    0,
1515    rtems_capture_cli_watch_list,
1516    { 0 },
1517    0
1518  },
1519  {
1520    "cwadd",
1521    "usage: cwadd [task name] [id]\n",
1522    0,
1523    rtems_capture_cli_watch_add,
1524    { 0 },
1525    0
1526  },
1527  {
1528    "cwdel",
1529    "usage: cwdel [task name] [id]\n",
1530    0,
1531    rtems_capture_cli_watch_del,
1532    { 0 },
1533    0
1534  },
1535  {
1536    "cwctl",
1537    "usage: cwctl [task name] [id] on/off\n",
1538    0,
1539    rtems_capture_cli_watch_control,
1540    { 0 },
1541    0
1542  },
1543  {
1544    "cwglob",
1545    "usage: cwglob on/off\n",
1546    0,
1547    rtems_capture_cli_watch_global,
1548    { 0 },
1549    0
1550  },
1551  {
1552    "cwceil",
1553    "usage: cwceil priority\n",
1554    0,
1555    rtems_capture_cli_watch_ceiling,
1556    { 0 },
1557    0
1558  },
1559  {
1560    "cwfloor",
1561    "usage: cwfloor priority\n",
1562    0,
1563    rtems_capture_cli_watch_floor,
1564    { 0 },
1565    0
1566  },
1567  {
1568    "ctrace",
1569    "usage: ctrace [-c] [-r records]\n",
1570    0,
1571    rtems_capture_cli_trace_records,
1572    { 0 },
1573    0
1574  },
1575  {
1576    "ctset",
1577    "usage: ctset -h\n",
1578    0,
1579    rtems_capture_cli_trigger_set,
1580    { 0 },
1581    0
1582  },
1583  {
1584    "ctclear",
1585    "usage: ctclear -?\n",
1586    0,
1587    rtems_capture_cli_trigger_clear,
1588    { 0 },
1589    0
1590  },
1591  {
1592    "cflush",
1593    "usage: cflush [-n]\n",
1594    0,
1595    rtems_capture_cli_flush,
1596    { 0 },
1597    0
1598  }
1599};
1600
1601/*
1602 * rtems_capture_cli_init
1603 *
1604 *  DESCRIPTION:
1605 *
1606 * This function initialises the command line interface to the capture
1607 * engine.
1608 *
1609 */
1610
1611rtems_status_code
1612rtems_capture_cli_init (rtems_capture_timestamp timestamp)
1613{
1614  int cmd;
1615
1616  capture_timestamp = timestamp;
1617
1618  for (cmd = 0;
1619       cmd < sizeof (rtems_capture_cli_cmds) / sizeof (rtems_monitor_command_entry_t);
1620       cmd++)
1621      rtems_monitor_insert_cmd (&rtems_capture_cli_cmds[cmd]);
1622
1623  return RTEMS_SUCCESSFUL;
1624}
Note: See TracBrowser for help on using the repository browser.