OpenROAD uses spdlog as part of logging infrastructure in order to ensure a clear, consistent messaging and complete messaging interface. A wrapper formats the prefix in the recommended messaging style and limit. A message format is as follows:
<tool id>-<message id> <Message body>.
For example,
[INFO ODB-0127] Reading DEF file: ./results/asap7/aes/base/4_cts.def
All output from OpenROAD tools should be directed through the logging API to ensure that redirection, file logging and execution control flow are handled consistently. This also includes messages from any third-party tool. Use the 'ord' message ID for third-party tools.
The logging infrastructure also supports generating a
JSON file containing design metrics (e.g., area or
slack). This output is directed to a user-specified file. The OpenROAD
application has a -metrics
command line argument to specify the file.
OpenROAD supports multiple levels of severity for message outputs: critical, error, warning, information and debug. These are supported by automatic calls to the logger which will then prefix the appropriate severity type to the message.
In C++20 the logger messages are checked during compile time which introduces restrictions around rutime format strings. See docs.
OpenROAD uses spdlog
which uses fmt_lib
under the hood. Below is an example of
what is no longer allowed.
In order to make use of runtime format strings, we have introduced a
FMT_RUNTIME
macro in Logger.h. You should use this macro any time you
pass a dynamic string as the format string
logger_->info("{} {}", a, b); // OK
void blah(std::string template& a) {
logger_->info(a, c); // Illegal
logger_->info(FMT_RUNTIME(a), c); // Ok
}
In addition to the proper use of message types, follow the guidelines below to compose messages for clarity, consistency and other guidelines:
Start with a capital letter and end with a period, besides well-known exceptions. Use capital letters for file formats and tool proper names, e.g., LEF, DEF, SPICE, FLUTE.
After the first word's capitalization, do not use capital letters (aside from obvious exceptions, such as RSMT, hCut, etc.).
Do not use exclamations. Severity must be communicated by message severity and clear implied or explicit action.
Avoid long, verbose messages. Use commas to list and separate clauses in messages.
Spellcheck all messages using American English spellings.
Use ellipsis ...
only to indicate a pause, as when some tool is
running or being initialized.
Use single-word versions when well-accepted / well-understood by users
and developers. Examples:
stdcell, cutline, wirelength, flipchip, padring, bondpad, wirebond, libcell, viarule
.
Do not abbreviate or truncate English words; expand for the sake of clarity.
Incorrect: Num, #; Tot.
Correct: Number; Total
Use acceptable, well-understood abbreviations for brevity. Examples:
db, tech, lib, inst, term, params, etc
.
Avoid contractions of action words:
Incorrect: Can't, Can not; Don't
Correct: Cannot; Do not
Messages should communicate a clear, implied or explicit action that is necessary for flow continuation or improved quality of results.
Example:
A value for core_area must be specified in the footprint specification, or in the environment variable CORE_AREA.
Messages must be clear and complete, so as to communicate necessary and sufficient information and actions. Elaborate specific variables, options, and/or parameters to avoid any ambiguity.
Example:
Unrecognized argument $arg, should be one of -pitch, -bump_pin_name, -spacing_to_edge, -cell_name, -bumps_per_tile, -rdl_layer, -rdl_width, -rdl_spacing.
Specify objects clearly in the local context:
Example:
cutWithin is smaller than cutSpacing for ADJACENTCUTS on layer {}. Please check your rule definition.
Incomplete:
Warning: {} does not have viaDef aligned with layer.
Make any assumptions or use of default values explicit:
Example:
No net slacks found.
Timing-driven mode disabled.
Incomplete, missing default:
Utilization exceeds 100%.
Use simple language, and avoid repetitions:
Example:
Missing orientation for cell $cell_ref.
Incorrect:
No orientation available for orientation of $cell_ref.
OpenROAD supports the following levels of severity through the logger: report, debug, information, warning, error and critical.
Report messages are output by the tool in the form of a report to the user. Examples include timing paths or power analysis results.
Example report message:
Path startpoint: $startpoint
Debug messages are only of use to tool developers and not to end users. These messages are not shown unless explicitly enabled.
Information messages may be used to report metrics, quality of results, or program status to the user. Any message which indicates runtime problems, such as potential faulty input or other internal program issues, should be issued at a higher status level.
Example information messages:
Number of input ports: 47
Running optimization iteration 2
Current cell site utilization: 57.1567%
Warnings should be used to indicate atypical runtime conditions that may affect quality, but not correctness, of the output. Any conditions that affect correctness should be issued at a higher status level.
Example warning messages:
Core area utilization is greater than 90%. The generated cell placement may not be routable.
14 outputs are not constrained for max capacitance.
Pin 'A[0]' on instance 'mem01' does not contain antenna information and will not be checked for antenna violations.
Error messages should be used to indicate correctness problems. Problems with command arguments are a good example of where error messages are appropriate. Errors exit the current command by throwing an exception that is converted to an error in Tcl. Errors that occur while reading a command file stop execution of the script commands.
Example error messages:
Invalid selection: net 'test0' does not exist in the design.
Cell placement cannot be run before floorplanning.
Argument 'max_routing_layer' expects an integer value from 1 to 10.
Critical messages should be used to indicate correctness problems that the program is not able to work around or ignore, and that require immediate exiting of the program (abort).
Example critical messages:
Database 'chip' has been corrupted and is not recoverable.
Unable to allocate heap memory for array 'vertexIndices'. The required memory size may exceed host machine limits.
Assertion failed: 'nodeVisited == false' on line 122 of example.cpp. Please file a Github issue and attach a testcase.
Each status message requires:
- The three letter tool ID
- The message ID
- The message string
- Optionally, additional arguments to fill in placeholders in the message string
Reporting is simply printing and does not require a tool or message ID.
The tool ID comes from a fixed enumeration of all the tools in the
system. This enumeration is in Logger.h
. New abbreviations should be
added after discussion with the OpenROAD system architects. The abbreviation
matches the C++ namespace for the tool.
Message IDs are integers. They are expected to be unique for each tool.
This has the benefit that a message can be mapped to the source code
unambiguously even if the text is not unique. Maintaining this invariant
is the tool owner's responsibility. To ensure that the IDs are unique,
each tool should maintain a file named 'messages.txt' in the top-level
tool directory, listing the message IDs along with the format string.
When code that uses a message ID is removed, the ID should be retired by
removing it from 'messages.txt'. See the utility
etc/find_messages.py
to scan a tool directory and write a
messages.txt
file.
Spdlog comes with the fmt
library which supports message formatting in a
python or C++20 like style.
The message string should not include the tool ID or message ID which will automatically be prepended. A trailing newline will automatically be added, and hence messages should not end with one. Messages should be written as complete sentences and end in a period. Multi-line messages may contain embedded new lines.
Some examples:
logger->report("Path startpoint: {}", startpoint);
logger->error(ODB, 25, "Unable to open LEF file {}.", file_name);
logger->info(DRT, 42, "Routed {} nets in {:3.2f}s.", net_count, elapsed_time);
Tcl functions for reporting messages are defined in the OpenROAD swig
file OpenRoad.i
. The message is simply a Tcl string (no C++20
formatting).
utl::report "Path startpoint: $startpoint"
utl::error ODB 25 "Unable to open LEF file $file_name."
utl::info DRT 42 "Routed $net_count nets in [format %3.2f $elapsed_time]."
utl::report
should be used instead of 'puts' so that all output is
logged.
Calls to the Tcl functions utl::warn
and utl::error
with a single
message argument report with tool ID UKN
and message ID 0000
.
Tools use #include utl/Logger.h
that defines the logger API. The Logger
instance is owned by the OpenROAD instance. Each tool should retrieve
the logger instance in the tool init function called after the tool make
function by the OpenROAD application.
Every tool swig file must include src/Exception.i so that errors thrown
by utl::error
are caught at the Tcl command level. Use the following
swig command before %inline
.
%include "../../Exception.i"
The logger functions are shown below.
Logger::report(const std::string& message,
const Args&... args)
Logger::info(ToolId tool,
int id,
const std::string& message,
const Args&... args)
Logger::warn(ToolId tool,
int id,
const std::string& message,
const Args&... args)
Logger::error(ToolId tool,
int id,
const std::string& message,
const Args&... args)
Logger::critical(ToolId tool,
int id,
const std::string& message,
const Args&... args)
The corresponding Tcl functions are shown below.
utl::report message
utl::info tool id message
utl::warn tool id message
utl::error tool id message
utl::critical tool id message
Although there is a utl::critical
function, it is really difficult to
imagine any circumstances that would justify aborting execution of the
application in a tcl function.
Debug messages have a different programming model. As they are most often not issued the concern is to avoid slowing down normal execution. For this reason such messages are issued by using the debugPrint macro. This macro will avoid evaluating its arguments if they are not going to be printed. The API is:
debugPrint(logger, tool, group, level, message, ...);
The debug()
method of the Logger class should not be called directly.
No message id is used as these messages are not intended for end users.
The level is printed as the message id in the output.
The argument types are as for the info/warn/error/critical messages.
The one additional argument is group which is a const char*
. Its
purpose is to allow the enabling of subsets of messages within one
tool.
Debug messages are enabled with the tcl command:
set_debug_level <tool> <group> <level>
The metrics logging uses a more restricted API since JSON only supports specific types. There are a set of overloaded methods of the form:
metric(ToolId tool,
const std::string_view metric,
<type> value)
where <type>
can be int, double, string, or bool
. This will result
in the generated JSON:
"<tool>-<metric>" : value
String values will be enclosed in double-quotes automatically.
The error functions in include/openroad/Error.hh
should no longer be
included or used. Use the corresponding logger functions.
All uses of the tcl functions ord::error and ord::warn should be updated
call the utl::error/warn
with a tool ID and message ID. For
compatibility these are defaulted to UKN
and 0000
until they are
updated.
Regression tests should not have any UKN-0000
messages in their ok
files. A simple grep should indicate that you still have pending calls
to pre-logger error/warn functions.
The cmake
file for the tool must also be updated to include spdlog in
the link libraries so it can find the header files if they are not in
the normal system directories.
:::{tip}
At UCSD, dfm.ucsd.edu is an example of this problem; it has an ancient version of
spdlog in '/usr/include/spdlog'. Use module
to install
spdlog 1.8.1 on dfm.ucsd.edu and check your build there.
:::
target_link_libraries(<library_target>
PUBLIC
utl
)
As tool developers, we can also choose to include useful information to the end user - be it in the form on debugging tips, or solutions to fix the errors/warnings. We compile a list of such errors in this table. The good thing about this page is the ability to encode rich formatting using Markdown, enabling you to convey more information than what can be said from the limited messages in code.
To format the information, refer to this sample GRT information file.
In addition, make sure you create the corresponding docs/messages
folder under the tool
folder,
before creating your Markdown file with the corresponding NUM
.
cd src/<tool> && mkdir -p doc/messages
cd doc/messages && touch <NUM>.md
A full list of tool namespaces can be found here.