source: rtems/cpukit/libmisc/capture/capture_support.c

Last change on this file was 4b7fbc7, checked in by Joel Sherrill <joel@…>, on 03/18/22 at 15:18:07

cpukit/libmisc/capture: Manually change license to BSD-2

These files did not follow the standard format and needed to be
changed manually.

Updates #3053.

  • Property mode set to 100644
File size: 14.2 KB
Line 
1/* SPDX-License-Identifier: BSD-2-Clause */
2
3/**
4 * @file
5 *
6 * @brief RTEMS Performance Monitoring and Measurement Framework.
7 *
8 * This is a set of print support routines that may be shared between
9 * the RTEMS monitor and direct callers of the capture engine.
10 */
11
12/*
13 * Copyright 2002, 2015 Chris Johns <chrisj@rtems.org>
14 * All rights reserved.
15 *
16 * COPYRIGHT (c) 1989-2014.
17 * On-Line Applications Research Corporation (OAR).
18 *
19 * Redistribution and use in source and binary forms, with or without
20 * modification, are permitted provided that the following conditions
21 * are met:
22 * 1. Redistributions of source code must retain the above copyright
23 *    notice, this list of conditions and the following disclaimer.
24 * 2. Redistributions in binary form must reproduce the above copyright
25 *    notice, this list of conditions and the following disclaimer in the
26 *    documentation and/or other materials provided with the distribution.
27 *
28 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
29 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
30 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
31 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
32 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
33 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
34 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
35 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
36 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
37 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
38 * POSSIBILITY OF SUCH DAMAGE.
39 */
40
41#ifdef HAVE_CONFIG_H
42#include "config.h"
43#endif
44
45#include <ctype.h>
46#include <stdlib.h>
47#include <stdio.h>
48#include <string.h>
49#include <inttypes.h>
50
51#include <rtems.h>
52#include <rtems/monitor.h>
53#include <rtems/captureimpl.h>
54
55/*
56 * Structure used during printing of the capture records.
57 */
58
59typedef struct
60{
61  const void*          recs;      /**< Next record to be read. */
62  size_t               read;      /**< Number of records read. */
63  size_t               printed;   /**< Records been printed. */
64  bool                 rec_valid; /**< The record is valid. */
65  rtems_capture_record rec;       /**< The record, copied out. */
66} ctrace_per_cpu;
67
68/*
69 * Task block size.
70 */
71#define CTRACE_TASK_BLOCK_SIZE (64)
72
73/**
74 * Task details from the task records used to print task names.
75 */
76typedef struct
77{
78  rtems_name name;
79  rtems_id   id;
80} ctrace_task_name;
81
82/**
83 * Structure to hold the tasks variables.
84 */
85typedef struct
86{
87  ctrace_task_name* tasks;
88  size_t            size;
89  size_t            count;
90} ctrace_tasks;
91
92/*
93 * Global so the records can span more than one trace.
94 */
95static ctrace_tasks tasks;
96
97/*
98 * Add a name.
99 */
100static void
101ctrace_task_name_add (rtems_id id, const rtems_name name)
102{
103  if (tasks.tasks == NULL)
104  {
105    tasks.size = CTRACE_TASK_BLOCK_SIZE;
106    tasks.tasks = calloc (tasks.size, sizeof (ctrace_task_name));
107  }
108  if (tasks.tasks != NULL)
109  {
110    if (rtems_object_id_get_api(id) != OBJECTS_POSIX_API)
111    {
112      size_t t;
113      for (t = 0; t < tasks.count; ++t)
114      {
115        if (tasks.tasks[t].id == id)
116        {
117          tasks.tasks[t].name = name;
118          break;
119        }
120      }
121      if (t == tasks.count)
122      {
123        if (tasks.count >= tasks.size)
124        {
125          tasks.size += CTRACE_TASK_BLOCK_SIZE;
126          tasks.tasks = realloc (tasks.tasks,
127                                 tasks.size * sizeof (ctrace_task_name));
128        }
129        if (tasks.tasks != NULL)
130        {
131          tasks.tasks[tasks.count].name = name;
132          tasks.tasks[tasks.count].id = id;
133          ++tasks.count;
134        }
135      }
136    }
137  }
138}
139
140/*
141 * Remove a task name.
142 */
143static void
144ctrace_task_name_remove (rtems_id id)
145{
146  size_t t;
147  for (t = 0; t < tasks.count; ++t)
148  {
149    if (tasks.tasks[t].id == id)
150    {
151      size_t count = tasks.count - t - 1;
152      if (count != 0)
153        memmove (&tasks.tasks[t],
154                 &tasks.tasks[t + 1],
155                 sizeof (ctrace_task_name) * count);
156      --tasks.count;
157      break;
158    }
159  }
160}
161
162/*
163 * Find a name.
164 */
165static void
166ctrace_task_name_find (rtems_id id, const rtems_name** name)
167{
168  size_t t;
169  *name = NULL;
170  for (t = 0; t < tasks.count; ++t)
171  {
172    if (tasks.tasks[t].id == id)
173    {
174      *name = &tasks.tasks[t].name;
175      break;
176    }
177  }
178}
179
180/*
181 * rtems_catpure_print_uptime
182 *
183 * This function prints the nanosecond uptime to stdout.
184 */
185void
186rtems_capture_print_timestamp (uint64_t uptime)
187{
188  uint32_t hours;
189  uint32_t minutes;
190  uint32_t seconds;
191  uint32_t nanosecs;
192  uint64_t up_secs;
193
194  up_secs  = uptime / 1000000000LLU;
195  minutes  = up_secs / 60;
196  hours    = minutes / 60;
197  minutes  = minutes % 60;
198  seconds  = up_secs % 60;
199  nanosecs = uptime % 1000000000;
200
201  fprintf (stdout, "%5" PRIu32 ":%02" PRIu32 ":%02" PRIu32".%09" PRIu32,
202             hours, minutes, seconds, nanosecs);
203}
204
205void
206rtems_capture_print_record_task (int                              cpu,
207                                 const rtems_capture_record*      rec,
208                                 const rtems_capture_task_record* task_rec)
209{
210  fprintf(stdout,"%2i ", cpu);
211  rtems_capture_print_timestamp (rec->time);
212  fprintf (stdout, "              ");
213  rtems_monitor_dump_id (rec->task_id);
214  if (rtems_object_id_get_api(rec->task_id) != OBJECTS_POSIX_API)
215  {
216    fprintf (stdout, " %c%c%c%c",
217             (char) (task_rec->name >> 24) & 0xff,
218             (char) (task_rec->name >> 16) & 0xff,
219             (char) (task_rec->name >> 8) & 0xff,
220             (char) (task_rec->name >> 0) & 0xff);
221  }
222  else
223  {
224    fprintf (stdout, " ____");
225  }
226  fprintf(stdout, " %3" PRId32 " %3" PRId32 " ",
227             (rec->events >> RTEMS_CAPTURE_REAL_PRIORITY_EVENT) & 0xff,
228             (rec->events >> RTEMS_CAPTURE_CURR_PRIORITY_EVENT) & 0xff);
229   fprintf (stdout, "%3" PRId32   " %6" PRId32 "  TASK_RECORD\n",
230            task_rec->start_priority,
231            task_rec->stack_size);
232}
233
234void
235rtems_capture_print_record_capture(int                         cpu,
236                                   const rtems_capture_record* rec,
237                                   uint64_t                    diff,
238                                   const rtems_name*           name)
239{
240  uint32_t event;
241  int      e;
242
243  event = rec->events >> RTEMS_CAPTURE_EVENT_START;
244  for (e = RTEMS_CAPTURE_EVENT_START; e < RTEMS_CAPTURE_EVENT_END; e++)
245  {
246    if (event & 1)
247    {
248      fprintf(stdout,"%2i ", cpu);
249      rtems_capture_print_timestamp (rec->time);
250      fprintf (stdout, " %12" PRId32 " ", (uint32_t) diff);
251      rtems_monitor_dump_id (rec->task_id);
252      if (name != NULL)
253      {
254        fprintf (stdout, " %c%c%c%c",
255                 (char) (*name >> 24) & 0xff,
256                 (char) (*name >> 16) & 0xff,
257                 (char) (*name >> 8) & 0xff,
258                 (char) (*name >> 0) & 0xff);
259      }
260      else
261      {
262        fprintf(stdout, "     ");
263      }
264      fprintf(stdout, " %3" PRId32 " %3" PRId32 "             %s\n",
265             (rec->events >> RTEMS_CAPTURE_REAL_PRIORITY_EVENT) & 0xff,
266             (rec->events >> RTEMS_CAPTURE_CURR_PRIORITY_EVENT) & 0xff,
267             rtems_capture_event_text (e));
268    }
269    event >>= 1;
270  }
271}
272
273/*
274 * rtems_capture_print_trace_records
275 *
276 * This function is a monitor command that dumps trace records.
277 */
278
279void
280rtems_capture_print_trace_records (int total, bool csv)
281{
282  ctrace_per_cpu*    per_cpu;
283  ctrace_per_cpu*    cpu;
284  int                cpus;
285  rtems_capture_time last_time = 0;
286  int                i;
287
288  cpus = rtems_scheduler_get_processor_maximum ();
289
290  per_cpu = calloc (cpus, sizeof(*per_cpu));
291  if (per_cpu == NULL)
292  {
293    fprintf(stdout, "error: no memory\n");
294    return;
295  }
296
297  while (total)
298  {
299    const rtems_capture_record* rec_out = NULL;
300    int                         cpu_out = -1;
301    rtems_capture_time          this_time = 0;
302
303    /* Prime the per_cpu data */
304    for (i = 0; i < cpus; i++) {
305      cpu = &per_cpu[i];
306
307      if (cpu->read == 0)
308      {
309        rtems_status_code sc;
310        sc = rtems_capture_read (i, &cpu->read, &cpu->recs);
311        if (sc != RTEMS_SUCCESSFUL)
312        {
313          fprintf (stdout,
314                   "error: trace read failed: %s\n", rtems_status_text (sc));
315          rtems_capture_flush (0);
316          free (per_cpu);
317          return;
318        }
319        /* Release the buffer if there are no records to read */
320        if (cpu->read == 0)
321          rtems_capture_release (i, 0);
322      }
323
324      /* Read the record out from the capture buffer */
325      if (!cpu->rec_valid && (cpu->read != 0))
326      {
327        cpu->recs = rtems_capture_record_extract (cpu->recs,
328                                                  &cpu->rec,
329                                                  sizeof (cpu->rec));
330        cpu->rec_valid = true;
331      }
332
333      /* Find the next record to print, the earliest recond on any core */
334      if ((cpu->rec_valid) && ((this_time == 0) || (cpu->rec.time < this_time)))
335      {
336        rec_out = &cpu->rec;
337        cpu_out = i;
338        this_time = rec_out->time;
339      }
340    }
341
342    /*  If we have read all the records abort. */
343    if (rec_out == NULL)
344      break;
345
346    cpu = &per_cpu[cpu_out];
347
348    /* Print the record */
349    if (csv)
350    {
351      fprintf(stdout,
352              "%03i,%08" PRIu32 ",%03" PRIu32
353              ",%03" PRIu32 ",%04" PRIx32 ",%" PRId64 "\n",
354              cpu_out,
355              (uint32_t) rec_out->task_id,
356              (rec_out->events >> RTEMS_CAPTURE_REAL_PRIORITY_EVENT) & 0xff,
357              (rec_out->events >> RTEMS_CAPTURE_CURR_PRIORITY_EVENT) & 0xff,
358              (rec_out->events >> RTEMS_CAPTURE_EVENT_START),
359              (uint64_t) rec_out->time);
360    }
361    else
362    {
363      if ((rec_out->events >> RTEMS_CAPTURE_EVENT_START) == 0)
364      {
365        rtems_capture_task_record task_rec;
366        cpu->recs = rtems_capture_record_extract (cpu->recs,
367                                                  &task_rec,
368                                                  sizeof (task_rec));
369        ctrace_task_name_add (rec_out->task_id, task_rec.name);
370        rtems_capture_print_record_task (cpu_out, rec_out, &task_rec);
371      }
372      else
373      {
374        rtems_capture_time diff;
375        const rtems_name*  name = NULL;
376        if (last_time != 0)
377          diff = rec_out->time - last_time;
378        else
379          diff = 0;
380        last_time = rec_out->time;
381        ctrace_task_name_find (rec_out->task_id, &name);
382        rtems_capture_print_record_capture (cpu_out, rec_out, diff, name);
383        if ((rec_out->events &
384             (RTEMS_CAPTURE_DELETED_BY_EVENT | RTEMS_CAPTURE_DELETED_EVENT)) != 0)
385          ctrace_task_name_remove (rec_out->task_id);
386      }
387    }
388
389    /*
390     * If we have not printed all the records read increment to the next
391     * record. If we have printed all records release the records printed.
392     */
393    cpu->rec_valid = false;
394    ++cpu->printed;
395    if (cpu->printed == cpu->read)
396    {
397      rtems_capture_release (cpu_out, cpu->printed);
398      cpu->recs = NULL;
399      cpu->read = 0;
400      cpu->printed = 0;
401    }
402
403    --total;
404  }
405
406  /* Finished so release all the records that were printed. */
407  for (i = 0; i < cpus; i++)
408  {
409    cpu = &per_cpu[i];
410    if (cpu->read != 0)
411    {
412      rtems_capture_release (i, cpu->printed);
413    }
414  }
415
416  free(per_cpu);
417}
418
419void
420rtems_capture_print_watch_list (void)
421{
422  rtems_capture_control* control = rtems_capture_get_control_list ();
423  rtems_task_priority    ceiling = rtems_capture_watch_get_ceiling ();
424  rtems_task_priority    floor = rtems_capture_watch_get_floor ();
425
426  fprintf (stdout, "watch priority ceiling is %" PRId32 "\n", ceiling);
427  fprintf (stdout, "watch priority floor is %" PRId32 "\n", floor);
428  fprintf (stdout, "global watch is %s\n",
429          rtems_capture_watch_global_on () ? "enabled" : "disabled");
430  fprintf (stdout, "total %" PRId32 "\n", rtems_capture_control_count ());
431
432  while (control)
433  {
434    uint32_t flags;
435    int      f;
436    int      fshowed;
437    int      lf;
438
439    fprintf (stdout, " ");
440    rtems_monitor_dump_id (rtems_capture_control_id (control));
441    fprintf (stdout, " ");
442    rtems_monitor_dump_name (rtems_capture_control_name (control));
443    flags = rtems_capture_control_flags (control);
444    fprintf (stdout, " %c%c ",
445             rtems_capture_watch_global_on () ? 'g' : '-',
446             flags & RTEMS_CAPTURE_WATCH ? 'w' : '-');
447    flags = rtems_capture_control_to_triggers (control);
448    fprintf (stdout, " T:%c%c%c%c%c%c%c",
449             flags & RTEMS_CAPTURE_SWITCH    ? 'S' : '-',
450             flags & RTEMS_CAPTURE_CREATE ? 'C' : '-',
451             flags & RTEMS_CAPTURE_START ? 'S' : '-',
452             flags & RTEMS_CAPTURE_RESTART ? 'R' : '-',
453             flags & RTEMS_CAPTURE_DELETE ? 'D' : '-',
454             flags & RTEMS_CAPTURE_BEGIN ? 'B' : '-',
455             flags & RTEMS_CAPTURE_EXITTED ? 'E' : '-');
456    flags = rtems_capture_control_from_triggers (control);
457    fprintf (stdout, " F:%c%c%c%c%c",
458             flags & RTEMS_CAPTURE_SWITCH  ? 'S' : '-',
459             flags & RTEMS_CAPTURE_CREATE  ? 'C' : '-',
460             flags & RTEMS_CAPTURE_START   ? 'S' : '-',
461             flags & RTEMS_CAPTURE_RESTART ? 'R' : '-',
462             flags & RTEMS_CAPTURE_DELETE  ? 'D' : '-');
463
464    for (f = 0, fshowed = 0, lf = 1; f < RTEMS_CAPTURE_TRIGGER_TASKS; f++)
465    {
466      if (rtems_capture_control_by_valid (control, f))
467      {
468        if (lf && ((fshowed % 3) == 0))
469        {
470          fprintf (stdout, "\n");
471          lf = 0;
472        }
473
474        fprintf (stdout, "  %2i:", f);
475        rtems_monitor_dump_name (rtems_capture_control_by_name (control, f));
476        fprintf (stdout, "/");
477        rtems_monitor_dump_id (rtems_capture_control_by_id (control, f));
478        flags = rtems_capture_control_by_triggers (control, f);
479        fprintf (stdout, ":%c%c%c%c%c",
480                 flags & RTEMS_CAPTURE_SWITCH  ? 'S' : '-',
481                 flags & RTEMS_CAPTURE_CREATE  ? 'C' : '-',
482                 flags & RTEMS_CAPTURE_START   ? 'S' : '-',
483                 flags & RTEMS_CAPTURE_RESTART ? 'R' : '-',
484                 flags & RTEMS_CAPTURE_DELETE  ? 'D' : '-');
485        fshowed++;
486        lf = 1;
487      }
488    }
489
490    if (lf)
491      fprintf (stdout, "\n");
492
493    control = rtems_capture_next_control (control);
494  }
495}
Note: See TracBrowser for help on using the repository browser.