libfoedus-core
FOEDUS Core Library
foedus::debugging Namespace Reference

Debug-Support functionalities. More...

Detailed Description

Debug-Support functionalities.

The engine provides API to turn on/of various debug-support functionalities.

Debug Logging with glog
We use the flexible debug-logging framework, Google-logging, or glog for short. Everyone who writes code in libfoedus should be familiar with glog. For example, use it as follows.
#include <glog/logging.h>
void your_func() {
VLOG(1) << "Entered your_func()"; // verbose debug log with level 1
LOG(INFO) << "some info. some_var=" << some_var; // debug log in INFO level
if (some_error_happened) {
LOG(ERROR) << "error!"; // debug log in ERROR level
}
}
Where Debug Logs are output
With the default settings, all logs are written to /tmp/libfoedus.'level', such as /tmp/libfoedus.INFO. LOG(ERROR) and LOG(FATAL) are also copied to stderr. Logs of specific execution are written to another file, /tmp/libfoedus.'hostname'.'user name'.log.'severity level'.'date'.'time'.'pid', such as: /tmp/libfoedus.hkimura-z820.kimurhid.log.INFO.20140406-215444.26946
DLOG and DVLOG
DLOG() and DVLOG() are completely disabled and wiped from our binary if our cmake build level is RELEASE or RELWITHDBGINFO. Most of our code each user transaction goes through should use only DLOG or DVLOG in its critical path.
Debug Logging Configurations
Although we don't expose glog classes themselves in our APIs, we provide our own APIs to configure them at both start-time and run-time for easier development. The start-time configuration is foedus::debugging::DebuggingOptions (foedus::EngineOptions::debug_). The run-time configuration APIs are provided by foedus::debugging::DebuggingSupports, which you can obtain via foedus::Engine::get_debug().
Debug Logging Level House-Rules
  • LOG(FATAL) is used where we are not ready for graceful shutdown. Eventually there should be none except asserting code bugs.
  • LOG(ERROR) is the default level for problemetic cases. Most error logging would be this. Do not use DLOG(ERROR). Instead always use LOG(ERROR).
  • LOG(WARNING) should be used only for expected and minor user-triggered errors. If it's either unexpected or major (eg out-of-disk is a user error, but worth raising as an error), use LOG(ERROR). You can use DLOG(WARNING) to avoid affecting performance in critical places.
  • For normal events that happen only once or a few times over very long time (seconds or more), then use LOG(INFO). For example, module initializations logs.
  • For more frequent normal events (hundreds/thousands per second), use DLOG(INFO).
  • For debug-messages that YOU wouldn't want to see unless you are writing code in that module, use VLOG. VLOG level 0: ~tens per second, 1: ~hundreds per second, 2: ~thousand per second. If it's more than thousand per second, do NOT use VLOG. It means (at least) that many level checkings per second! Use DLOG/DVLOG then.
Performance Counters
See foedus::debugging::StopWatch, foedus::debugging::RdtscWatch, and related methods.

Classes

struct  DebuggingOptions
 Set of options for debugging support. More...
 
class  DebuggingSupports
 APIs to support debugging functionalities. More...
 
class  RdtscWatch
 A RDTSC-based low-overhead stop watch. More...
 
class  StopWatch
 A high-resolution stop watch. More...
 

Functions

uint64_t get_rdtsc ()
 Returns the current CPU cycle via x86 RDTSC. More...
 
void wait_rdtsc_cycles (uint64_t cycles)
 Wait until the given CPU cycles elapse. More...
 
uint64_t get_now_nanosec ()
 

Variables

int static_glog_initialize_counter = 0
 This and static_glog_initialize_lock are the only static variables we have in the entire code base. More...
 
std::mutex static_glog_initialize_lock
 Exclusive lock variable for Google-logging's initialization/uninitialization. More...
 

Function Documentation

uint64_t foedus::debugging::get_now_nanosec ( )

Definition at line 25 of file stop_watch.cpp.

Referenced by foedus::debugging::StopWatch::peek_elapsed_ns(), foedus::debugging::StopWatch::start(), and foedus::debugging::StopWatch::stop().

25  {
26  std::chrono::high_resolution_clock::time_point now = std::chrono::high_resolution_clock::now();
27  return std::chrono::duration_cast<std::chrono::nanoseconds>(now.time_since_epoch()).count();
28 }

Here is the caller graph for this function:

Variable Documentation

int foedus::debugging::static_glog_initialize_counter = 0

This and static_glog_initialize_lock are the only static variables we have in the entire code base.

Because google-logging requires initialization/uninitialization only once in a process, we need this to coordinate it between multiple engines. We increment/decrement this after taking lock on static_glog_initialize_lock. The one who observed "0" as old value on increment, will initialize glog. The one who observed "1" as old value on decrement, will uninitialize glog.

Invariant
0 or larger. negative value is definitely a bug in synchronization code.

Definition at line 54 of file debugging_supports.cpp.

std::mutex foedus::debugging::static_glog_initialize_lock

Exclusive lock variable for Google-logging's initialization/uninitialization.

Each thread takes this mutex while init/uninit glog.

Definition at line 61 of file debugging_supports.cpp.