24 #include <sys/types.h>
29 #define NVSL_NODISCARD [[nodiscard]]
30 #define NVSL_UNUSED __attribute__((unused))
31 #define NVSL_EXPORT __attribute__((visibility("default")))
32 #define NVSL_NOINLINE __attribute__((noinline))
34 #define NVSL_BEGIN_IGNORE_WPEDANTIC \
35 _Pragma("GCC diagnostic push") \
36 _Pragma("GCC diagnostic ignored \"-Wpedantic\"")
38 #define NVSL_END_IGNORE_WPEDANTIC _Pragma("GCC diagnostic pop")
41 #define NVSL_LINE_NAME(prefix) NVSL_JOIN(prefix, __LINE__)
42 #define NVSL_JOIN(symbol1, symbol2) NVSL_DO_JOIN(symbol1, symbol2)
43 #define NVSL_DO_JOIN(symbol1, symbol2) symbol1##symbol2
46 #define NVSL_GUARD(mtx) \
47 std::lock_guard<std::mutex> NVSL_LINE_NAME(nvsl_macro_lock_guard)((mtx))
50 #define NVSL_GUARD_PTR(mtx) \
51 std::lock_guard<std::mutex> NVSL_LINE_NAME(nvsl_macro_lock_guard)((*mtx))
53 static const char *NVSL_LOG_LEVEL_ENV NVSL_UNUSED =
54 (
char *)(
"NVSL_LOG_LEVEL");
56 static std::ofstream nullstream;
58 extern std::ofstream log_st;
60 #define DBG 0 && std::cerr
61 #elif defined(NVSL_SIMPLIFIED_TERM_IO)
64 #define DBG (std::cerr)
69 inline bool wildcard(
const std::string &pat,
const std::string &str) {
70 return not fnmatch(pat.c_str(), str.c_str(), 0);
73 static inline bool is_log_enabled(
int level) {
76 const char *val = std::getenv(NVSL_LOG_LEVEL_ENV);
78 const std::string val_str = std::string(val);
81 log_lvl = std::stoul(val_str,
nullptr, 10);
84 throw std::out_of_range(
"Valid values: [0-4]");
86 }
catch (std::out_of_range &e) {
87 std::cerr <<
"LP FATAL: " << NVSL_LOG_LEVEL_ENV
88 <<
" is out of range. Valid values: [0-4]" << std::endl;
90 }
catch (std::invalid_argument &e) {
91 std::cerr <<
"LP FATAL: "
92 <<
"Unable to parse " << NVSL_LOG_LEVEL_ENV
93 <<
" env variable." << std::endl;
98 if (level <= log_lvl) {
105 static inline bool is_caller_enabled(
const std::string &caller) {
108 const char *val = std::getenv(NVSL_LOG_WILDCARD_ENV);
109 if (val !=
nullptr) {
110 const std::string val_str = std::string(val);
119 inline std::string nvsl_cur_time_str() {
120 std::stringstream ss;
122 auto now = std::chrono::system_clock::now();
123 auto timeNow = std::chrono::system_clock::to_time_t(now);
124 auto time_str = std::string(std::ctime(&timeNow));
126 ss << time_str.substr(0, time_str.length() - 1) <<
" [" << getpid() <<
"]";
134 DBGH(
const DBGH &obj) { this->enabled = obj.enabled; }
137 DBGH(uint8_t lvl,
const char *caller = __builtin_FUNCTION()) {
144 nvsl::is_log_enabled(lvl) && nvsl::is_caller_enabled(caller);
146 if (this->enabled) [[likely]] {
147 #ifdef NVSL_SIMPLIFIED_TERM_IO
148 DBG << lp_cur_time_str() <<
" | ";
150 DBG <<
"[\x1B[1m" << std::setw(20) << std::string(caller) <<
"()"
153 #endif // NVSL_SIMPLIFIED_TERM_IO
158 template <
typename T>
159 friend const DBGH &operator<<(
const DBGH &dbgh,
const T &obj);
161 friend const DBGH &operator<<(
const DBGH &s,
162 std::ostream &(*f)(std::ostream &));
163 friend const DBGH &operator<<(
const DBGH &s, std::ostream &(*f)(std::ios &));
164 friend const DBGH &operator<<(
const DBGH &s,
165 std::ostream &(*f)(std::ios_base &));
168 template <
typename T>
169 inline const DBGH &operator<<(
const DBGH &dbgh,
const T &obj) {
177 inline const DBGH &operator<<(
const DBGH &s,
178 std::ostream &(*f)(std::ostream &)) {
180 if (s.enabled) f(DBG);
185 inline const DBGH &operator<<(
const DBGH &s, std::ostream &(*f)(std::ios &)) {
187 if (s.enabled) f(DBG);
192 inline const DBGH &operator<<(
const DBGH &s,
193 std::ostream &(*f)(std::ios_base &)) {
195 if (s.enabled) f(DBG);
202 #define DBG 0 && std::cerr
204 #define DBGW (std::cerr << "Warning: ")
205 #define DBGE (std::cerr << "Error: ")
211 (DBGH(l) << std::string(__FUNCTION__) << "() called." << std::endl);
214 #ifdef NVSL_SIMPLIFIED_TERM_IO
215 #define DBGW (DBGH(0) << "Warning: ")
218 (DBG << "[\x1B[1m" << std::setw(20) << std::string(__FUNCTION__) << "()" \
220 << "]\x1B[95m WARNING: \x1B[0m")
224 #ifdef NVSL_SIMPLIFIED_TERM_IO
225 #define DBGE (DBG << "ERROR: \x1B[0m")
228 (DBG << "[\x1B[31m" << std::setw(20) << std::string(__FUNCTION__) << "()" \
230 << "]\x1B[95m ERROR: \x1B[0m")
236 static inline std::string ptr_to_string(
const void *addr) {
237 std::stringstream ss;
246 uint8_t *bptr = (uint8_t *)ptr;
247 auto result = (
void *)(((uint64_t)(bptr + 63) >> 6) << 6);
249 DBGH(4) <<
"Aligned " << (
void *)ptr <<
" -> " << (
void *)result
257 uint8_t *bptr = (uint8_t *)ptr;
258 auto result = (
void *)(((uint64_t)(bptr + (4 * KiB - 1)) >> 12) << 12);
260 DBGH(4) <<
"Aligned " << (
void *)ptr <<
" -> " << (
void *)result
268 uint8_t *bptr = (uint8_t *)ptr;
269 auto result = (
void *)(((uint64_t)(bptr + (2 * MiB - 1)) >> 21) << 21);
271 DBGH(4) <<
"Aligned " << (
void *)ptr <<
" -> " << (
void *)result
278 inline constexpr
auto round_bytes(
auto bytes,
auto mult) -> decltype(bytes) {
280 throw std::runtime_error(
"Mult " + std::to_string(mult) +
281 " is greater than bytes " +
282 std::to_string(bytes));
284 size_t alloc_bytes = bytes;
285 if (bytes % mult != 0) {
286 alloc_bytes = ((bytes / mult) + 1) * mult;
292 static inline std::string ptr_to_hexstr(
void *ptr) {
293 std::stringstream ss;
295 std::string result = ss.str();
302 template <
typename O,
typename I>
303 static inline O LP_RCast(I arg) {
304 return reinterpret_cast<O
>(arg);
308 template <
typename O,
typename I>
309 static inline O LP_SCast(I arg) {
310 return static_cast<O
>(arg);
314 template <
typename O,
typename I>
315 static inline O LP_DCast(I arg) {
316 return dynamic_cast<O
>(arg);
321 using retType = decltype(ptr);
323 auto ptr_ul = LP_RCast<uint64_t>(ptr);
324 return LP_RCast<retType>(ptr_ul >> 12);
333 static inline std::string __attribute__((__const__))
334 buf_to_hexstr(
const char *buf,
size_t bytes) {
335 std::stringstream result;
340 std::stringstream val;
341 while (cur_byte < bytes) {
342 result <<
"0x" << std::hex << std::setfill(
'0') << std::setw(8)
343 << ((uint64_t)(buf + cur_byte) >> 4) << 4 <<
" ";
344 for (
size_t i = 0; i < 16; i++) {
345 const size_t idx = cur_byte + i;
347 if (i % 4 == 0 && i != 0) {
351 uint32_t elem =
static_cast<uint8_t
>(buf[idx]);
352 result << std::hex << std::setfill(
'0') << std::setw(2)
353 << std::uppercase << elem;
355 if (buf[idx] >=
' ' and buf[idx] <=
'~') {
363 if (cur_byte < bytes) {
364 result <<
" " << val.str() << std::endl;
365 std::stringstream().swap(val);
372 inline bool is_pid_running(pid_t pid) {
373 while (waitpid(-1, 0, WNOHANG) > 0) {
377 if (0 == kill(pid, 0))
return 1;
382 template <
typename A,
typename B,
typename C>
383 inline uint64_t rebase_ptr(A old_base, B new_base, C ptr) {
385 (uint64_t)(new_base) + ((uint64_t)(ptr) - (uint64_t)(old_base));
386 DBGH(4) <<
"old_base: " << (
void *)(old_base)
387 <<
" new_base: " << (
void *)new_base
388 <<
" off: " << ((uint64_t)(ptr) - (uint64_t)(old_base))
389 <<
" result: " << (
void *)(result) << std::endl;
394 inline std::string ns_to_hr(
size_t ns_total) {
395 std::stringstream ss;
397 const size_t s = ns_total / (1000000000);
398 const size_t ms = (ns_total - s * 1000000000) / (1000000);
399 const size_t us = (ns_total - s * 1000000000 - ms * 1000000) / (1000);
401 (ns_total - s * 1000000000 - ms * 1000000 - us * 1000) / (1000);
403 ss << s <<
"s " << ms <<
"ms " << us <<
"us " << ns <<
"ns";
408 template <
typename T>
409 std::string to_latex(
const std::string &name, T val,
410 const std::string &suffix,
size_t div_factor = 1) {
412 double div_val = (int)((val / (
double)div_factor) / scale) * scale;
413 std::stringstream ss;
415 ss <<
"\\newcommand{\\" << name <<
"}{" << std::fixed
416 << std::setprecision(1) << div_val << suffix <<
"}";
421 std::string ns_to_latex(
size_t ns,
const std::string &name,
422 time_unit unit = time_unit::any_unit);
424 inline std::string uint64_to_base64(uint64_t val) {
425 std::string result =
"12345678901";
427 for (
size_t i = 0; i < 11; i++) {
428 uint8_t chunk = (val >> (i * 6)) & ((1 << 6) - 1);
429 result[i] = (char)(chunk +
' ');
434 inline uint64_t base64_to_uint64(std::string val) {
437 for (
size_t i = 0; i < 11; i++) {
438 result += (val[i] -
' ') << (i * 6);