Report Messages

Report (Debug and System) Messages

This may become a sub-project of GreenControl.

This documentation page currently presumes the reader's knowledge of the specification document.

Summary

This document summarizes the interfaces and some implementation details for SystemC report and debug information for both the system model user and system model creator.

This framework should eliminate printf or cout statements and provide a more flexible and centrally controllable mechanism. The mechanism will allow the integrator to completely compile out creator level debug (if desired), redirect output to stdout, file(s) or other outputs (see GreenAV project) and mask out system/debug statements based on severity/verbosity, or on a module-by-module basis, etc.

The intention is to have dedicated reporting mechanisms for System Messages (those which SystemC handles with sc_report and may be interesting for the user) and for Debug Messages (those which are often done with cout etc. and are interesting for the IP model creator). This mechanism should be flexible regarding the output target (cout, sc_report, log-files) and providing different levels of debug messages (L0-L9) and levels of system messages (the well-known sc_report levels). The mechanism should be able to filter the levels for different outputs.

Stream objects may be used as simple as cout is used.

Example (see also below):

  1. gs::report::gs_debug_stream b("my_dbg_stream1", gs::report::dbg_msg_L2);
  2. b << "message content" << std::endl
  3.   << "another line with stream content"
  4.   << GS_END_MSG; // End of message macro

Background

The usage of direct acess to stdout or files (e.g., via cout, printf, fprintf, etc) is forbidden for reusable IP models. The debug/system message facility is intended to be an easy to use replacement to cout, providing the convenience and familiarity of the "streaming" syntax of cout but with centralized control of the enable/disable mechanisms and file/stdout control. Debug and system messages (as opposed to user analsysis output) provide the IP model creator a facility to create messages which are a combination of data and strings. This is useful for conveying (for example) configuration errors or details of run-time state in a text/human readable format. The difference between debug and system messages is small, and they may rely on common underlying implementation.

First, system messages includes all official and documented message types (must be doc'ed in the IP Model spec/user guide) which are supported to the end user of the module and must not be compiled out of a given IP model. On the other hand, debug messages may include ad-hoc error messages that are likely to be only useful to the implementor of the IP. While it is permissible to not compile out the debug messages, a simple macro will exist that allows these messages to be completely eliminated from an IP model. (Note that if there is a requirement to not modify the compiled version of a model between that released outside to users (inside or outside TI) and that used internally by developers then this macro must be enabled).

Second, debug messages, at minimum, support filtering in terms of "verbosity". Whereas system messages, at minimum, support categorizing in terms of "severity". (there may be overlap provided by the implementation) E.g., for debug of a cycle accurate bus interface, if the user enables DEBUG_L0 then logical transactions may be printed, DEBUG_L1 will print physical transactions, and DEBUG_L2 could print all bus phases. (Note that "user supported" debug of this fictional bus interface, you would likely use either the Module Level Trace, or the User Analysis Info methodology which would allow custom massaging of the data under central control.) For system messages, the severity would be of type INFO, WARNING, ERROR, or FATAL.

In addition to the categorization of messages in terms of verbosity/severity, the IP provider can separate the streams based on IP specific partitioning. This is handled by creating multiple stream objects based on the internal functionality. E.g., the EDMA implementation may use unique stream operators to generate message streams for configuration info, configuration errors, TR processing, and event assertion. (Note that in contrast to the Module Trace requirements, the IP creator does not have to explicitly register the debug/system message object ... the registeration occurs within the constructor of those objects.)

Namespace

gs::report

Files

The framework files are located in greencontrol/reportmsg/*

A simple example which uses in-code configuration is located in greencontrol/examples/message_streamer_example/

An example using lua configuration is located in greencontrol/examples/message_streamer_lua_file_example/

Regression tests are located in greencontrol/examples/message_streamer_tests/

Features

For debug/system messages, the integrator/user should be able to enable/disable messages as follows:

  • List of message files
  • Per Message File:
    • Globally enable messages for a given module or subsystem
      • For Debug messages, selectively filter based on "Verbosity Level"
      • For System Messages, selectively enable for each Severity Level
    • Selectively enable specific message streams for a module based on "id" string.
      • If a specific stream is enabled, it can still be filtered based on verbosity/severity level, though this is a bit ambiguous since a given stream is defined at a fixed verbosity/severity level at construction.
    • Can enable and/or disable based on start and end time stamp.
    • Can optionally prepend:
      • sc_time_stamp (defaults to "enabled")
      • name() of parent module (defaults to "enabled")
      • file info (name/line#) of source message (defaults to "disabled")

 
The section 'Configuration' shows the user configurability. In summary, there are file specific settings (starttime, endtime, severity/verbosity, and enabling of prepended info (time, name, file). In addition, there are module/ID specific overrides provided for verbosity/severity levels.

Concept

active?fid=98

The figure shows a MessageStreamer class which is the one that does the output either to several special cases (stdout, stderr, sc_report_xxxx) or to file(s). There is existing system-wide only one object of this class which can be gotten with a static function (get_global_message_streamer()).

The user can apply the configuration to this object (adding new files/special cases with levels, time control)

  • either by calling apply_configuration with a message configuration object
  • or by configuring the MessageStreamer with a config file (classical or lua)

The user instantiates a stream object of class gs_debug_stream which can then be used according the specification. Messages can be streamed into it and are finalized with the macro GS_END_MSG.

What the user can do with this:

  • A user can enable several different output alternatives (files, stdout, sc_reports).
  • Each of these output alternatives gets all messages of the stream objects and can filter them individually
    • Filter by debug level
    • Filter by system level
    • Add/leave out module name of producer
    • Add/leave out sc time
    • Add/leave out file name and line number of message
  • Special settings for modules or even stream objects override the output alternative specific setting. (By disabling any levels.)

Stream Classes and Functions

gs_debug_stream(std::string _id, gs::report::debug_msg_level level)
or
gs_system_stream(std::string id, gs::report::system_msg_level level)
Constructor for the debug and system streams, respectively. Both constructors accept an "id" argument. The "id" is logically appended to the SystemC module hierarchy to uniquely identify each of the message streams in the system. Thus, the "id" for each stream within a module is unique. The Debug stream accepts a "verbosity" argument, which is an enum with possible values of dbg_msg_L0, dbg_msg_L1, dbg_msg_L2, ..., dbg_msg_L9. The System stream accepts a "severity" argument, which is an enum with possible values of sys_msg_INFO, sys_msg_WARNING, sys_msg_ERROR, or sys_msg_FATAL.
The constructor will register itself with the "stream messaging" infrastructure. The key information that is registered includes the module name, id, severity level, and verbosity level.

void enable(bool en = true);
This method is called by the infrastructure to enable or disable printing for this debug/system stream. The decision to enable/disable is made by the infrastructure, and is based on user configuration requesting a given modules+id, given verbosity/severity level, and the enable time has been reached or event has been detected. Defaults to "disabled" at construction.
When "enabled" the debug/system stream object will send data received via the input stream operator (<<) (after buffering) unformatted to the MessageStreamer object that has been gotten during construction by calling the static function MessageStreamer::get_global_message_streamer().

operator<<(...);
The stream class derives from std::ostringstream and accordingly supports all its streaming operators. They are used to stream the report into the report stream. This allows the use of the debug/system stream objects with a syntax that matches that used by the �cout� ostream object.

std::ostream& operator << (std::ostream &out, const GS_REPORTMSG_NAMESPACE::endmessage_type endm);
std::ostream& operator << (std::ostream &out, const GS_REPORTMSG_NAMESPACE::file_and_line_type fl)
Two special additional operators (outside the class) get the end message information and the file name and line information.

Stream Infrastructure Class

MessageStreamer
Streamer back-end class for debug and system message streamer. Directs the incoming report to the correct output dependent on the configuration. This class manages the configuration. See configuration section for details.
A single instance of the MessageStreamer class exists per System. All stream objects use a static get_global_message_streamer() function to access this instance. Configuration, formatting and output is managed by this class.

Rules

Steps how to make use of reports:

  • Enable or disable the messages (see #define below)
  • Include the stream header files
  • Apply configuration before first instantiation of a stream object (see configuration section)
  • Call gs::report::MessageStreamer::get_global_message_streamer(); in sc_main (at top-level!) before instantiating a stream object.
    (TODO: make it work without this)
  • Instantiate and use stream objects.

Configuration

The top-level testbench should define the output mechanism(s) (e.g. file, stdout, sc_report, ...).

There are several destined ways adding or configuring message configurations:

  • use a config file (classical or lua)
  • use message configuration objects,

Configuration abilities:

  • See specification
  • msgconfig_printlevel: If to prepend the message level.

Configuration with config files

You may configure the array of message configurations within the MessageStreamer directly using a config file. Take care to set all array positions beginning with 0.

Configure with classical config files

Example of a config file:

  1. ## file report output for all debug messages
  2.  
  3. MessageStreamer_config.0.msgconfig_name         "report_file_fix0.txt"
  4.  
  5. MessageStreamer_config.0.msgconfig_starttime_en false
  6.  
  7. MessageStreamer_config.0.msgconfig_dbglvl     9
  8. MessageStreamer_config.0.msgconfig_info_en    false
  9. MessageStreamer_config.0.msgconfig_warn_en    false
  10. MessageStreamer_config.0.msgconfig_error_en   false
  11. MessageStreamer_config.0.msgconfig_fatal_en   false
  12. MessageStreamer_config.0.msgconfig_printtime  true
  13. MessageStreamer_config.0.msgconfig_printname  true
  14. MessageStreamer_config.0.msgconfig_printfile  true
  15. MessageStreamer_config.0.msgconfig_printlevel true
  16.  
  17. MessageStreamer_config.0.msgconfig_module_id  "{"ModuleA", "ModuleB"}"
  18.  
  19.  
  20. ## file report output for all system messages
  21.  
  22. MessageStreamer_config.1.msgconfig_name         "report_file_fix1.txt"
  23.  
  24. MessageStreamer_config.1.msgconfig_starttime_en false
  25.  
  26. MessageStreamer_config.1.msgconfig_dbglvl     0
  27. MessageStreamer_config.1.msgconfig_info_en    true
  28. MessageStreamer_config.1.msgconfig_warn_en    true
  29. MessageStreamer_config.1.msgconfig_error_en   true
  30. MessageStreamer_config.1.msgconfig_fatal_en   true
  31. MessageStreamer_config.1.msgconfig_printtime  true
  32. MessageStreamer_config.1.msgconfig_printname  true
  33. MessageStreamer_config.1.msgconfig_printfile  false
  34. MessageStreamer_config.1.msgconfig_printlevel false

Configure with lua config files

Example of a lua config file:

  1. MessageStreamer_config = {
  2.   [0]={
  3.     msgconfig_name       = "report_file_fix0.txt",
  4.     msgconfig_starttime_en = false,
  5.     msgconfig_dbglvl     = 9,
  6.     msgconfig_info_en    = false,
  7.     msgconfig_warn_en    = false,
  8.     msgconfig_error_en   = false,
  9.     msgconfig_fatal_en   = false,
  10.     msgconfig_printtime  = true,
  11.     msgconfig_printname  = true,
  12.     msgconfig_printfile  = true,
  13.     msgconfig_printlevel = true,
  14.     msgconfig_module_id  = "{\"ModuleA\", \"ModuleB\"}"
  15.   },
  16.   {
  17.     msgconfig_name       = "report_file_fix1.txt",
  18.     msgconfig_starttime_en = false,
  19.     msgconfig_dbglvl     = 0,
  20.     msgconfig_info_en    = true,
  21.     msgconfig_warn_en    = true,
  22.     msgconfig_error_en   = true,
  23.     msgconfig_fatal_en   = true,
  24.     msgconfig_printtime  = true,
  25.     msgconfig_printname  = true,
  26.     msgconfig_printfile  = false,
  27.     msgconfig_printlevel = false
  28.   }
  29. }

Notice the [0]= prefix before the first member. (TODO: may be changed in lua parser?)

Configuration with message configuration objects

To add a new output, create an instance of msg_configuration (see figure) and set its members.

This mechanism can be used additionally to config files, but after having instantiated the MessageStreamer.

This configuration object has to be given to the static function gs::report::MessageStreamer::apply_configuration(msg_configuration_object)

You may keep this configuration object and change it and give it another time to the function. If the a config object with an already given file name is given to the function, the output will be changed to use the new settings. This may be done at any time point.

See example greencontrol/examples/message_streamer_example.

active?fid=99

Code example creating and applying a file configuration:

  1. gs::report::msg_configuration cnf;
  2. cnf.msgconfig_name = "report_message_file1.txt";
  3. cnf.msgconfig_starttime_en = true;
  4. cnf.msgconfig_starttime = sc_core::sc_time(13, sc_core::SC_NS);
  5. cnf.msgconfig_endtime = sc_core::sc_time(23, sc_core::SC_NS);
  6. cnf.msgconfig_dbglvl = gs::report::dbg_msg_L9;
  7. cnf.msgconfig_printfile = true;
  8. cnf.msgconfig_module_id.push_back("ModuleA"); // ModuleA
  9. cnf.msgconfig_module_id.push_back(""); // top-level
  10. gs::report::MessageStreamer::apply_configuration(cnf);

Compile base removal of report messages

In each compiled file the following macro should be defined (before including the report message files) to enable/disable the messages that are surrounded by the GS_DEBUG macro.

  1. #define GS_DEBUG_EN 0 // to disable report messages
  2. #define GS_DEBUG_EN 1 // to enable report messages

Example Code

Includes:
  1. // message streamer
  2. #define GS_MSG_DEBUG_EN 1
  3. #include "greencontrol/reportmsg/gs_debug_stream.h"
  4. #include "greencontrol/reportmsg/gs_system_stream.h"

Module that does three different levels of debug report messages and uses info system messages:

  1. class ModuleA
  2. : sc_core::sc_module
  3. {
  4. protected:
  5.   gs::report::gs_debug_stream dbgL2;
  6.   gs::report::gs_debug_stream dbgL4;
  7.   gs::report::gs_debug_stream dbgL9;
  8.   gs::report::gs_system_stream sysINFO;
  9.  
  10. public:
  11.   SC_HAS_PROCESS(ModuleA);
  12.   ModuleA(sc_core::sc_module_name name)
  13.   : sc_module(name)
  14.   , dbgL2("dbgL2", gs::report::dbg_msg_L2)
  15.   , dbgL4("dbgL4", gs::report::dbg_msg_L4)
  16.   , dbgL9("dbgL9", gs::report::dbg_msg_L9)
  17.   , sysINFO("sysINFO", gs::report::sys_msg_INFO)
  18.   {
  19.     SC_THREAD(main_action);
  20.   }
  21.  
  22.   void main_action() {
  23.     wait(10, sc_core::SC_NS);
  24.  
  25.     dbgL2 << "Hallo L2" << GS_END_MSG;
  26.    
  27.     dbgL9 << "Hallo L9" << std::endl << "new line" << GS_END_MSG;
  28.    
  29.     wait(10, sc_core::SC_NS);
  30.  
  31.     sysINFO << "This is an sc_info!" << GS_END_MSG;
  32.  
  33.     dbgL4 << "Hallo L4" << std::endl << "new line" << GS_END_MSG;
  34.   }
  35.  
  36. };

Testbench that defines several outputs:

  1. int sc_main(int argc, char *argv[]) {
  2.  
  3.   GS_INIT_STANDARD_GREENCONTROL; // Macro creating Core and Config- and GAV-Plugin
  4.  
  5.   // Parse lua file and apply configuration directly
  6.   gs::cnf::LuaFile_Tool luareader("luareader");
  7.   luareader.config("message_file_config.lua");
  8.   // --- ALTERNATIVE: ---
  9.   // Parse config file and apply configuration directly
  10.   gs::cnf::ConfigFile_Tool configTool("ConfigFileTool");
  11.   configTool.config("message_file_config.cfg");
  12.  
  13.   gs::report::MessageStreamer::get_global_message_streamer();
  14.  
  15.   gs::report::file_configuration cnf;
  16.   cnf.msgconfig_name = "report_message_file1.txt";
  17.   cnf.msgconfig_starttime_en = false;
  18.   cnf.msgconfig_dbglvl = gs::report::dbg_msg_L9;
  19.   cnf.msgconfig_printtime = true;
  20.   cnf.msgconfig_printname = true;
  21.   cnf.msgconfig_printfile = true;
  22.   gs::report::MessageStreamer::apply_configuration(cnf);
  23.  
  24.   gs::report::file_configuration cnf2;
  25.   cnf2.msgconfig_name = "stdout";
  26.   cnf2.msgconfig_starttime_en = false;
  27.   cnf2.msgconfig_dbglvl = gs::report::dbg_msg_L6;
  28.   cnf2.msgconfig_printtime = true;
  29.   cnf2.msgconfig_printname = true;
  30.   cnf2.msgconfig_printfile = true;
  31.   gs::report::MessageStreamer::apply_configuration(cnf2);
  32.  
  33.   // instantiate first stream object _after_ configured with file configuration and called get_global_message_streamer()
  34.   ModuleA moda("ModuleA");
  35.  
  36.   sc_start();
  37. }

The levels for debug and system messages are:
active?fid=93

Technical internals

  • Simulation preparations
    • The GreenAV plugin needs to be in place
    • The static global object MessageStreamer object is instantiated once.
  • Streaming
    • The user instantiates as many objects as needed of the classes gs::report::gs_debug_stream and gs::report::gs_system_stream.
    • These objects derive from report_stream which derives from ostringstream.
    • The stream objects register themselves at the MessageStreamer object with their message level.
    • When streaming messages into the streaming objects, the stream is directed to the base ostringstream.
    • The streaming of the end macro GS_END_MSG causes a call to the global MessageStreamer object which then does the output following its configurattion (see below).
  • Configuration
    • Configuration is performed only at the one global MessageStreamer object, not at the particular stream objects.
    • File configuration means that for the whole system several outputs can be defined (configured) each of them handling the messages it is configured to handle. See section Configuration for details on the configuration options.
    • Configuration can be done on two ways:
      • Create file_configuration objects whose members represent configuration details being applied to the MessageStreamer internal configuration when calling function add_file_config(file_configuration)
      • Read a ConfigSet from a (usual but dedicated) config file and call function apply_config_set(ConfigSet). The config set members represent a file configuration and are applied to the internal configuration similar to the file configuration mechanism. The config set is checked for a parameter name 'msgconfig_name' and if it is there, the this and the other members are searched and applied. So far the config set is allowed to contain only one file configuration.