Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:24:18

0001 /* SPDX-License-Identifier: BSD-2-Clause */
0002 
0003 /**
0004  * @file
0005  *
0006  * @brief RTEMS Performance Monitoring and Measurement Framework.
0007  *
0008  * This is a set of print support routines that may be shared between
0009  * the RTEMS monitor and direct callers of the capture engine.
0010  */
0011 
0012 /*
0013  * Copyright 2002, 2015 Chris Johns <chrisj@rtems.org>
0014  * All rights reserved.
0015  *
0016  * COPYRIGHT (c) 1989-2014.
0017  * On-Line Applications Research Corporation (OAR).
0018  *
0019  * Redistribution and use in source and binary forms, with or without
0020  * modification, are permitted provided that the following conditions
0021  * are met:
0022  * 1. Redistributions of source code must retain the above copyright
0023  *    notice, this list of conditions and the following disclaimer.
0024  * 2. Redistributions in binary form must reproduce the above copyright
0025  *    notice, this list of conditions and the following disclaimer in the
0026  *    documentation and/or other materials provided with the distribution.
0027  *
0028  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0029  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0030  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0031  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0032  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0033  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0034  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0035  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0036  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0037  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0038  * POSSIBILITY OF SUCH DAMAGE.
0039  */
0040 
0041 #ifdef HAVE_CONFIG_H
0042 #include "config.h"
0043 #endif
0044 
0045 #include <ctype.h>
0046 #include <stdlib.h>
0047 #include <stdio.h>
0048 #include <string.h>
0049 #include <inttypes.h>
0050 
0051 #include <rtems.h>
0052 #include <rtems/monitor.h>
0053 #include <rtems/captureimpl.h>
0054 
0055 /*
0056  * Structure used during printing of the capture records.
0057  */
0058 
0059 typedef struct
0060 {
0061   const void*          recs;      /**< Next record to be read. */
0062   size_t               read;      /**< Number of records read. */
0063   size_t               printed;   /**< Records been printed. */
0064   bool                 rec_valid; /**< The record is valid. */
0065   rtems_capture_record rec;       /**< The record, copied out. */
0066 } ctrace_per_cpu;
0067 
0068 /*
0069  * Task block size.
0070  */
0071 #define CTRACE_TASK_BLOCK_SIZE (64)
0072 
0073 /**
0074  * Task details from the task records used to print task names.
0075  */
0076 typedef struct
0077 {
0078   rtems_name name;
0079   rtems_id   id;
0080 } ctrace_task_name;
0081 
0082 /**
0083  * Structure to hold the tasks variables.
0084  */
0085 typedef struct
0086 {
0087   ctrace_task_name* tasks;
0088   size_t            size;
0089   size_t            count;
0090 } ctrace_tasks;
0091 
0092 /*
0093  * Global so the records can span more than one trace.
0094  */
0095 static ctrace_tasks tasks;
0096 
0097 /*
0098  * Add a name.
0099  */
0100 static void
0101 ctrace_task_name_add (rtems_id id, const rtems_name name)
0102 {
0103   if (tasks.tasks == NULL)
0104   {
0105     tasks.size = CTRACE_TASK_BLOCK_SIZE;
0106     tasks.tasks = calloc (tasks.size, sizeof (ctrace_task_name));
0107   }
0108   if (tasks.tasks != NULL)
0109   {
0110     if (rtems_object_id_get_api(id) != OBJECTS_POSIX_API)
0111     {
0112       size_t t;
0113       for (t = 0; t < tasks.count; ++t)
0114       {
0115         if (tasks.tasks[t].id == id)
0116         {
0117           tasks.tasks[t].name = name;
0118           break;
0119         }
0120       }
0121       if (t == tasks.count)
0122       {
0123         if (tasks.count >= tasks.size)
0124         {
0125           tasks.size += CTRACE_TASK_BLOCK_SIZE;
0126           tasks.tasks = realloc (tasks.tasks,
0127                                  tasks.size * sizeof (ctrace_task_name));
0128         }
0129         if (tasks.tasks != NULL)
0130         {
0131           tasks.tasks[tasks.count].name = name;
0132           tasks.tasks[tasks.count].id = id;
0133           ++tasks.count;
0134         }
0135       }
0136     }
0137   }
0138 }
0139 
0140 /*
0141  * Remove a task name.
0142  */
0143 static void
0144 ctrace_task_name_remove (rtems_id id)
0145 {
0146   size_t t;
0147   for (t = 0; t < tasks.count; ++t)
0148   {
0149     if (tasks.tasks[t].id == id)
0150     {
0151       size_t count = tasks.count - t - 1;
0152       if (count != 0)
0153         memmove (&tasks.tasks[t],
0154                  &tasks.tasks[t + 1],
0155                  sizeof (ctrace_task_name) * count);
0156       --tasks.count;
0157       break;
0158     }
0159   }
0160 }
0161 
0162 /*
0163  * Find a name.
0164  */
0165 static void
0166 ctrace_task_name_find (rtems_id id, const rtems_name** name)
0167 {
0168   size_t t;
0169   *name = NULL;
0170   for (t = 0; t < tasks.count; ++t)
0171   {
0172     if (tasks.tasks[t].id == id)
0173     {
0174       *name = &tasks.tasks[t].name;
0175       break;
0176     }
0177   }
0178 }
0179 
0180 /*
0181  * rtems_catpure_print_uptime
0182  *
0183  * This function prints the nanosecond uptime to stdout.
0184  */
0185 void
0186 rtems_capture_print_timestamp (uint64_t uptime)
0187 {
0188   uint32_t hours;
0189   uint32_t minutes;
0190   uint32_t seconds;
0191   uint32_t nanosecs;
0192   uint64_t up_secs;
0193 
0194   up_secs  = uptime / 1000000000LLU;
0195   minutes  = up_secs / 60;
0196   hours    = minutes / 60;
0197   minutes  = minutes % 60;
0198   seconds  = up_secs % 60;
0199   nanosecs = uptime % 1000000000;
0200 
0201   fprintf (stdout, "%5" PRIu32 ":%02" PRIu32 ":%02" PRIu32".%09" PRIu32,
0202              hours, minutes, seconds, nanosecs);
0203 }
0204 
0205 void
0206 rtems_capture_print_record_task (int                              cpu,
0207                                  const rtems_capture_record*      rec,
0208                                  const rtems_capture_task_record* task_rec)
0209 {
0210   fprintf(stdout,"%2i ", cpu);
0211   rtems_capture_print_timestamp (rec->time);
0212   fprintf (stdout, "              ");
0213   rtems_monitor_dump_id (rec->task_id);
0214   if (rtems_object_id_get_api(rec->task_id) != OBJECTS_POSIX_API)
0215   {
0216     fprintf (stdout, " %c%c%c%c",
0217              (char) (task_rec->name >> 24) & 0xff,
0218              (char) (task_rec->name >> 16) & 0xff,
0219              (char) (task_rec->name >> 8) & 0xff,
0220              (char) (task_rec->name >> 0) & 0xff);
0221   }
0222   else
0223   {
0224     fprintf (stdout, " ____");
0225   }
0226   fprintf(stdout, " %3" PRId32 " %3" PRId32 " ",
0227              (rec->events >> RTEMS_CAPTURE_REAL_PRIORITY_EVENT) & 0xff,
0228              (rec->events >> RTEMS_CAPTURE_CURR_PRIORITY_EVENT) & 0xff);
0229    fprintf (stdout, "%3" PRId32   " %6" PRId32 "  TASK_RECORD\n",
0230             task_rec->start_priority,
0231             task_rec->stack_size);
0232 }
0233 
0234 void
0235 rtems_capture_print_record_capture(int                         cpu,
0236                                    const rtems_capture_record* rec,
0237                                    uint64_t                    diff,
0238                                    const rtems_name*           name)
0239 {
0240   uint32_t event;
0241   int      e;
0242 
0243   event = rec->events >> RTEMS_CAPTURE_EVENT_START;
0244   for (e = RTEMS_CAPTURE_EVENT_START; e < RTEMS_CAPTURE_EVENT_END; e++)
0245   {
0246     if (event & 1)
0247     {
0248       fprintf(stdout,"%2i ", cpu);
0249       rtems_capture_print_timestamp (rec->time);
0250       fprintf (stdout, " %12" PRId32 " ", (uint32_t) diff);
0251       rtems_monitor_dump_id (rec->task_id);
0252       if (name != NULL)
0253       {
0254         fprintf (stdout, " %c%c%c%c",
0255                  (char) (*name >> 24) & 0xff,
0256                  (char) (*name >> 16) & 0xff,
0257                  (char) (*name >> 8) & 0xff,
0258                  (char) (*name >> 0) & 0xff);
0259       }
0260       else
0261       {
0262         fprintf(stdout, "     ");
0263       }
0264       fprintf(stdout, " %3" PRId32 " %3" PRId32 "             %s\n",
0265              (rec->events >> RTEMS_CAPTURE_REAL_PRIORITY_EVENT) & 0xff,
0266              (rec->events >> RTEMS_CAPTURE_CURR_PRIORITY_EVENT) & 0xff,
0267              rtems_capture_event_text (e));
0268     }
0269     event >>= 1;
0270   }
0271 }
0272 
0273 /*
0274  * rtems_capture_print_trace_records
0275  *
0276  * This function is a monitor command that dumps trace records.
0277  */
0278 
0279 void
0280 rtems_capture_print_trace_records (int total, bool csv)
0281 {
0282   ctrace_per_cpu*    per_cpu;
0283   ctrace_per_cpu*    cpu;
0284   int                cpus;
0285   rtems_capture_time last_time = 0;
0286   int                i;
0287 
0288   cpus = rtems_scheduler_get_processor_maximum ();
0289 
0290   per_cpu = calloc (cpus, sizeof(*per_cpu));
0291   if (per_cpu == NULL)
0292   {
0293     fprintf(stdout, "error: no memory\n");
0294     return;
0295   }
0296 
0297   while (total)
0298   {
0299     const rtems_capture_record* rec_out = NULL;
0300     int                         cpu_out = -1;
0301     rtems_capture_time          this_time = 0;
0302 
0303     /* Prime the per_cpu data */
0304     for (i = 0; i < cpus; i++) {
0305       cpu = &per_cpu[i];
0306 
0307       if (cpu->read == 0)
0308       {
0309         rtems_status_code sc;
0310         sc = rtems_capture_read (i, &cpu->read, &cpu->recs);
0311         if (sc != RTEMS_SUCCESSFUL)
0312         {
0313           fprintf (stdout,
0314                    "error: trace read failed: %s\n", rtems_status_text (sc));
0315           rtems_capture_flush (0);
0316           free (per_cpu);
0317           return;
0318         }
0319         /* Release the buffer if there are no records to read */
0320         if (cpu->read == 0)
0321           rtems_capture_release (i, 0);
0322       }
0323 
0324       /* Read the record out from the capture buffer */
0325       if (!cpu->rec_valid && (cpu->read != 0))
0326       {
0327         cpu->recs = rtems_capture_record_extract (cpu->recs,
0328                                                   &cpu->rec,
0329                                                   sizeof (cpu->rec));
0330         cpu->rec_valid = true;
0331       }
0332 
0333       /* Find the next record to print, the earliest recond on any core */
0334       if ((cpu->rec_valid) && ((this_time == 0) || (cpu->rec.time < this_time)))
0335       {
0336         rec_out = &cpu->rec;
0337         cpu_out = i;
0338         this_time = rec_out->time;
0339       }
0340     }
0341 
0342     /*  If we have read all the records abort. */
0343     if (rec_out == NULL)
0344       break;
0345 
0346     cpu = &per_cpu[cpu_out];
0347 
0348     /* Print the record */
0349     if (csv)
0350     {
0351       fprintf(stdout,
0352               "%03i,%08" PRIu32 ",%03" PRIu32
0353               ",%03" PRIu32 ",%04" PRIx32 ",%" PRId64 "\n",
0354               cpu_out,
0355               (uint32_t) rec_out->task_id,
0356               (rec_out->events >> RTEMS_CAPTURE_REAL_PRIORITY_EVENT) & 0xff,
0357               (rec_out->events >> RTEMS_CAPTURE_CURR_PRIORITY_EVENT) & 0xff,
0358               (rec_out->events >> RTEMS_CAPTURE_EVENT_START),
0359               (uint64_t) rec_out->time);
0360     }
0361     else
0362     {
0363       if ((rec_out->events >> RTEMS_CAPTURE_EVENT_START) == 0)
0364       {
0365         rtems_capture_task_record task_rec;
0366         cpu->recs = rtems_capture_record_extract (cpu->recs,
0367                                                   &task_rec,
0368                                                   sizeof (task_rec));
0369         ctrace_task_name_add (rec_out->task_id, task_rec.name);
0370         rtems_capture_print_record_task (cpu_out, rec_out, &task_rec);
0371       }
0372       else
0373       {
0374         rtems_capture_time diff;
0375         const rtems_name*  name = NULL;
0376         if (last_time != 0)
0377           diff = rec_out->time - last_time;
0378         else
0379           diff = 0;
0380         last_time = rec_out->time;
0381         ctrace_task_name_find (rec_out->task_id, &name);
0382         rtems_capture_print_record_capture (cpu_out, rec_out, diff, name);
0383         if ((rec_out->events &
0384              (RTEMS_CAPTURE_DELETED_BY_EVENT | RTEMS_CAPTURE_DELETED_EVENT)) != 0)
0385           ctrace_task_name_remove (rec_out->task_id);
0386       }
0387     }
0388 
0389     /*
0390      * If we have not printed all the records read increment to the next
0391      * record. If we have printed all records release the records printed.
0392      */
0393     cpu->rec_valid = false;
0394     ++cpu->printed;
0395     if (cpu->printed == cpu->read)
0396     {
0397       rtems_capture_release (cpu_out, cpu->printed);
0398       cpu->recs = NULL;
0399       cpu->read = 0;
0400       cpu->printed = 0;
0401     }
0402 
0403     --total;
0404   }
0405 
0406   /* Finished so release all the records that were printed. */
0407   for (i = 0; i < cpus; i++)
0408   {
0409     cpu = &per_cpu[i];
0410     if (cpu->read != 0)
0411     {
0412       rtems_capture_release (i, cpu->printed);
0413     }
0414   }
0415 
0416   free(per_cpu);
0417 }
0418 
0419 void
0420 rtems_capture_print_watch_list (void)
0421 {
0422   rtems_capture_control* control = rtems_capture_get_control_list ();
0423   rtems_task_priority    ceiling = rtems_capture_watch_get_ceiling ();
0424   rtems_task_priority    floor = rtems_capture_watch_get_floor ();
0425 
0426   fprintf (stdout, "watch priority ceiling is %" PRId32 "\n", ceiling);
0427   fprintf (stdout, "watch priority floor is %" PRId32 "\n", floor);
0428   fprintf (stdout, "global watch is %s\n",
0429           rtems_capture_watch_global_on () ? "enabled" : "disabled");
0430   fprintf (stdout, "total %" PRId32 "\n", rtems_capture_control_count ());
0431 
0432   while (control)
0433   {
0434     uint32_t flags;
0435     int      f;
0436     int      fshowed;
0437     int      lf;
0438 
0439     fprintf (stdout, " ");
0440     rtems_monitor_dump_id (rtems_capture_control_id (control));
0441     fprintf (stdout, " ");
0442     rtems_monitor_dump_name (rtems_capture_control_name (control));
0443     flags = rtems_capture_control_flags (control);
0444     fprintf (stdout, " %c%c ",
0445              rtems_capture_watch_global_on () ? 'g' : '-',
0446              flags & RTEMS_CAPTURE_WATCH ? 'w' : '-');
0447     flags = rtems_capture_control_to_triggers (control);
0448     fprintf (stdout, " T:%c%c%c%c%c%c%c",
0449              flags & RTEMS_CAPTURE_SWITCH    ? 'S' : '-',
0450              flags & RTEMS_CAPTURE_CREATE ? 'C' : '-',
0451              flags & RTEMS_CAPTURE_START ? 'S' : '-',
0452              flags & RTEMS_CAPTURE_RESTART ? 'R' : '-',
0453              flags & RTEMS_CAPTURE_DELETE ? 'D' : '-',
0454              flags & RTEMS_CAPTURE_BEGIN ? 'B' : '-',
0455              flags & RTEMS_CAPTURE_EXITTED ? 'E' : '-');
0456     flags = rtems_capture_control_from_triggers (control);
0457     fprintf (stdout, " F:%c%c%c%c%c",
0458              flags & RTEMS_CAPTURE_SWITCH  ? 'S' : '-',
0459              flags & RTEMS_CAPTURE_CREATE  ? 'C' : '-',
0460              flags & RTEMS_CAPTURE_START   ? 'S' : '-',
0461              flags & RTEMS_CAPTURE_RESTART ? 'R' : '-',
0462              flags & RTEMS_CAPTURE_DELETE  ? 'D' : '-');
0463 
0464     for (f = 0, fshowed = 0, lf = 1; f < RTEMS_CAPTURE_TRIGGER_TASKS; f++)
0465     {
0466       if (rtems_capture_control_by_valid (control, f))
0467       {
0468         if (lf && ((fshowed % 3) == 0))
0469         {
0470           fprintf (stdout, "\n");
0471           lf = 0;
0472         }
0473 
0474         fprintf (stdout, "  %2i:", f);
0475         rtems_monitor_dump_name (rtems_capture_control_by_name (control, f));
0476         fprintf (stdout, "/");
0477         rtems_monitor_dump_id (rtems_capture_control_by_id (control, f));
0478         flags = rtems_capture_control_by_triggers (control, f);
0479         fprintf (stdout, ":%c%c%c%c%c",
0480                  flags & RTEMS_CAPTURE_SWITCH  ? 'S' : '-',
0481                  flags & RTEMS_CAPTURE_CREATE  ? 'C' : '-',
0482                  flags & RTEMS_CAPTURE_START   ? 'S' : '-',
0483                  flags & RTEMS_CAPTURE_RESTART ? 'R' : '-',
0484                  flags & RTEMS_CAPTURE_DELETE  ? 'D' : '-');
0485         fshowed++;
0486         lf = 1;
0487       }
0488     }
0489 
0490     if (lf)
0491       fprintf (stdout, "\n");
0492 
0493     control = rtems_capture_next_control (control);
0494   }
0495 }