Page MenuHomec4science

lm_log.cc
No OneTemporary

File Metadata

Created
Thu, Jun 27, 12:58

lm_log.cc

/**
* @file lm_log.cc
*
* @author Guillaume Anciaux <guillaume.anciaux@epfl.ch>
*
* @date Mon Sep 08 23:40:22 2014
*
* @brief Log/Debug system of LibMultiScale
*
* @section LICENSE
*
* Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne)
* Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides)
*
* LibMultiScale is free software: you can redistribute it and/or modify it
* under the
* terms of the GNU Lesser General Public License as published by the Free
* Software Foundation, either version 3 of the License, or (at your option) any
* later version.
*
* LibMultiScale is distributed in the hope that it will be useful, but
* WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
* A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
* details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with LibMultiScale. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "action_interface.hh"
#include "factory_multiscale.hh"
#include "lm_common.hh"
#include "lm_globals.hh"
#include <cxxabi.h>
#include <execinfo.h>
#include <fstream>
#include <iomanip>
#include <iostream>
#include <mpi.h>
#include <unistd.h>
/* -------------------------------------------------------------------------- */
__BEGIN_LIBMULTISCALE__
/* -------------------------------------------------------------------------- */
#define CREATE_SEGFAULT \
if (create_seg_fault) { \
UInt *a = NULL; \
*a = 1; \
}
/* -------------------------------------------------------------------------- */
void doWait(bool condition) {
if (!condition)
return;
UInt pid = lm_getpid();
std::cerr << "Proc " << lm_my_proc_id << " Waiting for gdb to attach: pid is "
<< pid << std::endl;
UInt a = 1;
while (a) {
};
}
/* -------------------------------------------------------------------------- */
void doWaitOnFatal() { doWait(wait_on_fatal); }
/* -------------------------------------------------------------------------- */
void doWaitAtStartup() {
doWait((wait_at_startup != UINT_MAX) && (lm_my_proc_id == wait_at_startup));
}
/* -------------------------------------------------------------------------- */
std::string exec(const std::string &cmd) {
FILE *pipe = popen(cmd.c_str(), "r");
if (!pipe)
return "";
char buffer[1024];
std::string result = "";
while (!feof(pipe)) {
if (fgets(buffer, 128, pipe) != nullptr)
result += buffer;
}
result = result.substr(0, result.size() - 1);
pclose(pipe);
return result;
}
/* -------------------------------------------------------------------------- */
static inline std::map<std::string, size_t> getAddressMap() {
std::string me = "";
char buf[1024];
/* The manpage says it won't null terminate. Let's zero the buffer. */
memset(buf, 0, sizeof(buf));
/* Note we use sizeof(buf)-1 since we may need an extra char for NUL. */
if (readlink("/proc/self/exe", buf, sizeof(buf) - 1))
me = std::string(buf);
// std::cerr << "me = " << me << std::endl;
std::ifstream inmaps;
std::map<std::string, size_t> addr_map;
inmaps.open("/proc/self/maps");
std::string line;
while (inmaps.good()) {
std::getline(inmaps, line);
std::stringstream sstr(line);
size_t first = line.find('-');
std::stringstream sstra(line.substr(0, first));
size_t addr;
sstra >> std::hex >> addr;
std::string lib;
sstr >> lib;
sstr >> lib;
sstr >> lib;
sstr >> lib;
sstr >> lib;
sstr >> lib;
if (lib != "" && addr_map.find(lib) == addr_map.end()) {
addr_map[lib] = addr;
}
}
return addr_map;
}
/* -------------------------------------------------------------------------- */
static inline LMStackTrace get_stacktrace() {
UInt max_frames = 512;
std::vector<void *> stack_addrs(max_frames);
char **stack_strings;
size_t stack_depth = backtrace(stack_addrs.data(), max_frames);
stack_strings = backtrace_symbols(stack_addrs.data(), stack_depth);
std::list<std::string> stack_trace;
for (UInt i = 0; i < stack_depth - 2; ++i) {
stack_trace.push_back(stack_strings[i]);
}
free(stack_strings);
std::map<std::string, size_t> addr_map = getAddressMap();
return LMStackTrace(stack_trace, addr_map);
}
/** Print a demangled stack backtrace of the caller function to a string */
inline std::string print_stacktrace(LMStackTrace stack_trace,
UInt max_frames = 10) {
std::map<std::string, size_t> addr_map = getAddressMap();
auto stack_list = stack_trace.stack;
std::vector<std::string> stack{std::begin(stack_list), std::end(stack_list)};
std::stringstream mesg_stream;
mesg_stream << "\n==== C++ stack trace ==== \n";
int max = std::min<int>(max_frames, stack.size() - 1);
for (UInt i = max; i > 1; i--) {
std::string bt_line(stack[i]);
size_t first, second;
if ((first = bt_line.find('(')) != std::string::npos &&
(second = bt_line.find('+')) != std::string::npos) {
std::string location = bt_line.substr(0, first);
std::string location_cmd =
std::string("/bin/readlink") + std::string(" -f ") + location;
location = exec(location_cmd);
std::string call =
demangle(bt_line.substr(first + 1, second - first - 1).c_str());
size_t f = bt_line.find('[');
size_t s = bt_line.find(']');
std::string address = bt_line.substr(f + 1, s - f - 1);
std::stringstream sstra(address);
size_t addr;
sstra >> std::hex >> addr;
// mesg_stream << location << " [" << call << "]";
// std::cerr << "AAAA " << sstra.str() << " " << call << std::endl;
auto it = stack_trace.addr_map.find(location);
if (it != stack_trace.addr_map.end()) {
std::stringstream syscom;
syscom << "/usr/bin/addr2line"
<< " 0x" << std::hex << (addr - it->second) << " -i -e "
<< location;
// std::cerr << "AAAA " << syscom.str() << std::endl;
std::string line = exec(syscom.str());
// std::cerr << "AAAA " << line << std::endl;
std::replace(line.begin(), line.end(), ' ', ':');
mesg_stream << line << ": " << std::endl;
} else {
mesg_stream << location << ":0x" << std::hex << addr << std::endl;
}
} else {
mesg_stream << bt_line << std::endl;
}
}
return mesg_stream.str();
}
/* -------------------------------------------------------------------------- */
LMStackTrace::LMStackTrace(std::list<std::string> stack,
std::map<std::string, size_t> addr_map)
: stack(stack), addr_map(addr_map) {}
/** Print a demangled stack backtrace of the caller function to a string */
// static inline std::string print_stacktrace2(UInt max_frames = 10) {
// std::string mesg;
// mesg += "\n==== C++ stack trace ==== \n";
// // storage array for stack trace address data
// std::vector<void *> addrlist(max_frames);
// // retrieve current stack addresses
// int addrlen = backtrace(addrlist.data(), addrlist.size());
// if (addrlen == 0) {
// mesg += " <empty, possibly corrupt>\n";
// return mesg;
// }
// addrlist.resize(addrlen);
// // resolve addresses into strings containing "filename(function+address)",
// // this array must be free()-ed
// auto symbollist = backtrace_symbols(addrlist.data(), addrlist.size());
// // iterate over the returned symbol lines. skip the first, it is the
// // address of this function.
// for (UInt i = addrlist.size() - 1; i > 0; i--) {
// char *begin_name = 0, *begin_offset = 0, *end_offset = 0;
// // find parentheses and +address offset surrounding the mangled name:
// // ./module(function+0x15c) [0x8048a6d]
// for (char *p = symbollist[i]; *p; ++p) {
// if (*p == '(')
// begin_name = p;
// else if (*p == '+')
// begin_offset = p;
// else if (*p == ')' && begin_offset) {
// end_offset = p;
// break;
// }
// }
// if (begin_name && begin_offset && end_offset && begin_name <
// begin_offset) {
// *begin_name++ = '\0';
// *begin_offset++ = '\0';
// *end_offset = '\0';
// // mangled name is now in [begin_name, begin_offset) and caller
// // offset in [begin_offset, end_offset). now apply
// // __cxa_demangle():
// int status;
// decltype(auto) ret = abi::__cxa_demangle(begin_name, NULL, NULL,
// &status);
// std::string funcname;
// if (status == 0) {
// funcname = ret;
// free(ret);
// } else
// funcname = begin_name;
// mesg += symbollist[i];
// mesg += " : " + funcname + "+" + begin_offset + "\n";
// } else {
// // couldn't parse the line? print the whole line.
// mesg += symbollist[i];
// mesg += "\n";
// }
// }
// free(symbollist);
// return mesg;
// }
/* -------------------------------------------------------------------------- */
void lmFatal(std::stringstream &x, UInt line, const std::string &file,
const std::string &, const std::string &) {
if (!fatal_loop) {
fatal_loop = true;
try {
auto &actions = ActionManager::getManager();
current_stage = PRE_FATAL;
actions.action();
} catch (...) {
}
}
std::stringstream sstr;
sstr << file << ":" << line << ":FATAL: (" << current_step << ")"
<< "[" << lm_my_proc_id << "]:" << x.str() << std::endl;
// (*global_out) << sstr.str();
// (*global_out).flush();
CREATE_SEGFAULT;
DOWAIT_ON_FATAL;
throw LibMultiScaleException(sstr.str());
CREATE_SEGFAULT;
// ::libmultiscale::lm_exit(LM_EXIT_FAILURE);
}
/* -------------------------------------------------------------------------- */
void lmFatal_rethrow(LibMultiScaleException &e, std::stringstream &x, UInt line,
const std::string &file, const std::string &,
const std::string &) {
if (!fatal_loop) {
fatal_loop = true;
try {
auto &actions = ActionManager::getManager();
current_stage = PRE_FATAL;
actions.action();
} catch (...) {
}
}
std::stringstream sstr;
sstr << file << ":" << line << ":FATAL: (" << current_step << ")"
<< "[" << lm_my_proc_id << "]:" << x.str() << std::endl;
// (*global_out) << sstr.str();
// (*global_out).flush();
CREATE_SEGFAULT;
DOWAIT_ON_FATAL;
throw LibMultiScaleException(e, sstr.str());
CREATE_SEGFAULT;
// ::libmultiscale::lm_exit(LM_EXIT_FAILURE);
}
/* -------------------------------------------------------------------------- */
LibMultiScaleException::LibMultiScaleException(const std::string &mess) throw()
: message(mess), stack_trace(get_stacktrace()) {
previous_exception = nullptr;
}
LibMultiScaleException::LibMultiScaleException(const LibMultiScaleException &e,
const std::string &mess) throw()
: message(mess), stack_trace(get_stacktrace()) {
previous_exception = std::make_shared<LibMultiScaleException>(e);
}
const char *LibMultiScaleException::what() const throw() {
return message.c_str();
}
std::string LibMultiScaleException::recursiveWhat() {
std::stringstream sstr;
sstr << message;
std::string recursive_message = sstr.str();
if (previous_exception != nullptr)
recursive_message = previous_exception->recursiveWhat() + "\n" +
"-----------------------------------------" +
"-----------------------------------------\n" +
recursive_message;
return recursive_message;
}
std::string LibMultiScaleException::messageWithTrace() {
std::stringstream sstr;
std::string mesg = print_stacktrace(this->stack_trace);
sstr << mesg << "\n\n" << message;
std::string message_with_trace = sstr.str();
if (previous_exception != nullptr)
message_with_trace = previous_exception->messageWithTrace() + "\n" +
"-----------------------------------------" +
"-----------------------------------------\n" +
message_with_trace;
return message_with_trace;
}
void openGlobal() {
if (print_crap_to_file) {
std::stringstream sstr;
sstr << my_hostname << "-" << lm_my_proc_id << ".log";
file_out.open(sstr.str().c_str(), std::ios_base::out);
global_out = &file_out;
} else {
global_out = &std::cerr;
}
}
/* -------------------------------------------------------------------------- */
inline std::ostream &operator<<(std::ostream &stream, const dbgLevel &_this) {
switch (_this) {
case dbg_message:;
break;
case dbg_warning:
stream << "WARNING:";
break;
case dbg_info_startup:
stream << "INFO_STARTUP:";
break;
case dbg_info:
stream << "INFO:";
break;
case dbg_detail:
stream << "DETAIL:";
break;
case dbg_all:
stream << "ALL:";
break;
}
return stream;
}
/* -------------------------------------------------------------------------- */
#define INFO_PROCESS \
"s=" << current_step << ":" << current_stage << ":proc=" << lm_my_proc_id \
<< ": "
#define INFO_PROCESS_FULL \
"s=" << current_step << ":" << current_stage << ":proc=" << lm_my_proc_id \
<< ":host=" << my_hostname << "," << lm_getpid() << " : "
#define INFO_SOURCE function << ":" << line << ":"
#define INFO_SOURCE_FULL file << ":" << line << ":" << pretty_function << ":"
/* ----------------- */
// no info
//#define APPEND_FILE ""
/* ------------------*/
// small info
#define APPEND_FILE INFO_SOURCE << INFO_PROCESS
/* ------------------*/
// full info
//#define APPEND_FILE INFO_SOURCE_FULL << INFO_PROCESS_FULL
/* -------------------------------------------------------------------------- */
void lmPrintOut(std::stringstream &x, dbgLevel level, UInt line,
const std::string &file [[gnu::unused]],
const std::string &function [[gnu::unused]],
const std::string &pretty_function [[gnu::unused]]) {
if (global_level >= level)
if ((global_proc == lm_uint_max || global_proc == lm_my_proc_id ||
global_proc1 == lm_my_proc_id || global_proc2 == lm_my_proc_id) &&
(current_step >= start_dump &&
(end_dump == lm_uint_max || current_step <= end_dump))) {
if (global_out)
(*global_out) << APPEND_FILE << x.str() << std::endl << std::flush;
}
}
/* -------------------------------------------------------------------------- */
__END_LIBMULTISCALE__

Event Timeline