Logging - Errors - Assertions

vtr_log

This header defines useful logging macros for VTR projects.

Message Type

Three types of log message types are defined:

  • VTR_LOG : The standard ‘info’ type log message

  • VTR_LOG_WARN : A warning log message. This represents unusual condition that may indicate an issue but executiom continues

  • VTR_LOG_ERROR : An error log message. This represents a clear issue that should result in stopping the program execution. Please note that using this log message will not actually terminate the program. So a VtrError should be thrown after all the neccessary VTR_LOG_ERROR messages are printed.

For example:

 VTR_LOG("This produces a regular '%s' message\n", "info");
 VTR_LOG_WARN("This produces a '%s' message\n", "warning");
 VTR_LOG_ERROR("This produces an '%s' message\n", "error");

Conditional Logging

Each of the three message types also have a VTR_LOGV_* variant, which will cause the message to be logged if a user-defined condition is satisifed.

For example:

 VTR_LOGV(verbosity > 5, "This message will be logged only if verbosity is greater than %d\n", 5);
 VTR_LOGV_WARN(verbose, "This warning message will be logged if verbose is true\n");
 VTR_LOGV_ERROR(false, "This error message will never be logged\n");

Custom Location Logging

Each of the three message types also have a VTR_LOGF_* variant, which will cause the message to be logged for a custom file and

For example:

 VTR_LOGF("my_file.txt", "This message will be logged from file 'my_file.txt' line %d\n", 42);

Debug Logging

For debug purposes it may be useful to have additional logging. This is supported by VTR_LOG_DEBUG() and VTR_LOGV_DEBUG().

To avoid run-time overhead, these are only enabled if VTR_ENABLE_DEBUG_LOGGING is defined (disabled by default).

namespace vtr

std::optional-like interface with optional references. currently: import TartanLlama’s optional into the vtr namespace documentation at https://tl.tartanllama.xyz/en/latest/api/optional.html there are three main uses of this:

  1. replace pointers when refactoring legacy code optional<T&> (reference) is in many ways a pointer, it even has * and -> operators, but it can’t be allocated or freed. this property is very helpful in refactoring.

  2. explicit alternative for containers optional<T> (non-reference) allows you to put non-empty-initializable objects into a container which owns them. it is an alternative to unique_ptr<T> in that sense, but with a cleaner interface.

  3. function return types returning an optional<T> gives the caller a clear hint to check the return value.

Q: why not use std::optional? A: std::optional doesn’t allow optional<T&> due to a disagreement about what it means to assign to an optional reference. tl::optional permits this, with “rebind on assignment” behavior. this means opt<T&> acts very similarly to a pointer. Q: why do we need opt<T&>? there’s already T*. A: in an ideal world where all pointers are aliases to existing values and nothing else, opt<T&> wouldn’t be that necessary. however VPR is full of legacy code where the usual C++ conventions about pointers don’t apply. when refactoring such code, turning all pointers into opt<T&> helps a lot. it can’t be allocated or freed and doesn’t allow pointer arithmetic. in that aspect it acts as a “enforced proper C++ ptr”. that’s why I think it’s worth keeping around in the codebase.

Functions

void add_warnings_to_suppress(std::string function_name)

The following data structure and functions allow to suppress noisy warnings and direct them into an external file, if specified.

void set_noisy_warn_log_file(std::string log_file_name)

This function creates a new log file to hold the suppressed warnings. If the file already exists, it is cleared out first.

void print_or_suppress_warning(const char *pszFileName, unsigned int lineNum, const char *pszFuncName, const char *pszMessage, ...)

This function checks whether to print or to suppress warning.

This function checks whether the function from which the warning has been called is in the set of warnings_to_suppress. If so, the warning is printed on the noisy_warn_log_file, otherwise it is printed on stdout (or the regular log file)

vtr_error

A utility container that can be used to identify VTR execution errors.

The recommended usage is to store information in this container about the error during an error event and and then throwing an exception with the container. If the exception is not handled (exception is not caught), this will result in the termination of the program.

Error information can be displayed using the information stored within this container.

namespace vtr

std::optional-like interface with optional references. currently: import TartanLlama’s optional into the vtr namespace documentation at https://tl.tartanllama.xyz/en/latest/api/optional.html there are three main uses of this:

  1. replace pointers when refactoring legacy code optional<T&> (reference) is in many ways a pointer, it even has * and -> operators, but it can’t be allocated or freed. this property is very helpful in refactoring.

  2. explicit alternative for containers optional<T> (non-reference) allows you to put non-empty-initializable objects into a container which owns them. it is an alternative to unique_ptr<T> in that sense, but with a cleaner interface.

  3. function return types returning an optional<T> gives the caller a clear hint to check the return value.

Q: why not use std::optional? A: std::optional doesn’t allow optional<T&> due to a disagreement about what it means to assign to an optional reference. tl::optional permits this, with “rebind on assignment” behavior. this means opt<T&> acts very similarly to a pointer. Q: why do we need opt<T&>? there’s already T*. A: in an ideal world where all pointers are aliases to existing values and nothing else, opt<T&> wouldn’t be that necessary. however VPR is full of legacy code where the usual C++ conventions about pointers don’t apply. when refactoring such code, turning all pointers into opt<T&> helps a lot. it can’t be allocated or freed and doesn’t allow pointer arithmetic. in that aspect it acts as a “enforced proper C++ ptr”. that’s why I think it’s worth keeping around in the codebase.

class VtrError : public std::runtime_error
#include <vtr_error.h>

Container that holds information related to an error.

It holds different info related to a VTR error:

  • error message

  • file name associated with the error

  • line number associated with the error

Example Usage:

 // creating and throwing an exception with a VtrError container that has an error occuring in file "error_file.txt" at line number 1

 throw vtr::VtrError("This is a program terminating error!", "error_file.txt", 1);

Public Functions

inline VtrError(std::string msg = "", std::string new_filename = "", size_t new_linenumber = -1)

VtrError constructor.

inline std::string filename() const

gets the filename

Returns the filename associated with this error. Returns an empty string if none is specified.

inline const char *filename_c_str() const

same as filename() but returns in c style string

inline size_t line() const

get the line number

Returns the line number associated with this error. Returns zero if none is specified.

vtr_assertion

The header vtr_assert.h defines useful assertion macros for VTR projects.

Four types of assertions are defined:

 VTR_ASSERT_OPT   - low overhead assertions that should always be enabled
 VTR_ASSERT       - medium overhead assertions that are usually be enabled
 VTR_ASSERT_SAFE  - high overhead assertions typically enabled only for debugging
 VTR_ASSERT_DEBUG - very high overhead assertions typically enabled only for extreme debugging
Each of the above assertions also have a *_MSG variants (e.g. VTR_ASSERT_MSG(expr, msg)) which takes an additional argument specifying additional message text to be shown. By convention the message should state the condition being checked (and not the failure condition), since that the condition failed is obvious from the assertion failure itself.

The macro VTR_ASSERT_LEVEL specifies the level of assertion checking desired and is updated in CMAKE compilation:

 VTR_ASSERT_LEVEL == 4: VTR_ASSERT_OPT, VTR_ASSERT, VTR_ASSERT_SAFE, VTR_ASSERT_DEBUG enabled
 VTR_ASSERT_LEVEL == 3: VTR_ASSERT_OPT, VTR_ASSERT, VTR_ASSERT_SAFE enabled
 VTR_ASSERT_LEVEL == 2: VTR_ASSERT_OPT, VTR_ASSERT enabled
 VTR_ASSERT_LEVEL == 1: VTR_ASSERT_OPT enabled
 VTR_ASSERT_LEVEL == 0: No assertion checking enabled
@Note that an assertion levels beyond 4 are currently treated the same as level 4 and the default assertion level is 2

vtr_time

class ScopedStartFinishTimer : public vtr::ScopedActionTimer

Scoped elapsed time class which prints out the action when initialized and again both the action and elapsed time.

when destructed. For example:

  {
      vtr::ScopedStartFinishTimer timer("my_action") //Will print: 'my_action'

      //Do other work

      //Will print 'my_action took X.XX seconds' when out of scope
  }

class ScopedFinishTimer : public vtr::ScopedActionTimer

Scoped elapsed time class which prints the time elapsed for the specified action when it is destructed.

For example:

  {
      vtr::ScopedFinishTimer timer("my_action");

      //Do other work

      //Will print: 'my_action took X.XX seconds' when out-of-scope
  }

class ScopedActionTimer : public vtr::Timer

Scoped time class which prints the time elapsed for the specifid action.

Subclassed by vtr::ScopedFinishTimer, vtr::ScopedStartFinishTimer

class Timer

Class for tracking time elapsed since construction.

Subclassed by vtr::ScopedActionTimer