Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

src: implement per-process native Debug() printer and use it in mkcodecache #31884

Closed
wants to merge 7 commits into from
Closed
20 changes: 20 additions & 0 deletions node.gyp
Original file line number Diff line number Diff line change
Expand Up @@ -1225,6 +1225,16 @@
],

'conditions': [
[ 'node_use_openssl=="true"', {
Copy link
Member Author

@joyeecheung joyeecheung Feb 25, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just realized that these are necessary for the headers (esp. enums) to match in mkcodecache and node_mksnapshot binaries - hopefully all these cruft can be cleaned up when #31074 is addressed, though the last time I tried SmartOS wouldn't link, sigh.

'defines': [
'HAVE_OPENSSL=1',
],
}],
['v8_enable_inspector==1', {
'defines': [
'HAVE_INSPECTOR=1',
],
}],
['OS=="win"', {
'libraries': [
'dbghelp.lib',
Expand Down Expand Up @@ -1269,6 +1279,16 @@
],

'conditions': [
[ 'node_use_openssl=="true"', {
'defines': [
'HAVE_OPENSSL=1',
],
}],
['v8_enable_inspector==1', {
'defines': [
'HAVE_INSPECTOR=1',
],
}],
['OS=="win"', {
'libraries': [
'Dbghelp.lib',
Expand Down
2 changes: 1 addition & 1 deletion src/aliased_buffer.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
#if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS

#include <cinttypes>
#include "util.h"
#include "util-inl.h"
#include "v8.h"

namespace node {
Expand Down
88 changes: 88 additions & 0 deletions src/debug_utils-inl.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS

#include "debug_utils.h"
#include "env.h"

#include <type_traits>

Expand Down Expand Up @@ -90,6 +91,93 @@ void COLD_NOINLINE FPrintF(FILE* file, const char* format, Args&&... args) {
FWrite(file, SPrintF(format, std::forward<Args>(args)...));
}

template <typename... Args>
inline void FORCE_INLINE Debug(EnabledDebugList* list,
DebugCategory cat,
const char* format,
Args&&... args) {
if (!UNLIKELY(list->enabled(cat))) return;
FPrintF(stderr, format, std::forward<Args>(args)...);
}

inline void FORCE_INLINE Debug(EnabledDebugList* list,
DebugCategory cat,
const char* message) {
if (!UNLIKELY(list->enabled(cat))) return;
FPrintF(stderr, "%s", message);
}

template <typename... Args>
inline void FORCE_INLINE
Debug(Environment* env, DebugCategory cat, const char* format, Args&&... args) {
Debug(env->enabled_debug_list(), cat, format, std::forward<Args>(args)...);
}

inline void FORCE_INLINE Debug(Environment* env,
DebugCategory cat,
const char* message) {
Debug(env->enabled_debug_list(), cat, message);
}

template <typename... Args>
inline void Debug(Environment* env,
DebugCategory cat,
const std::string& format,
Args&&... args) {
Debug(env->enabled_debug_list(),
cat,
format.c_str(),
std::forward<Args>(args)...);
}

// Used internally by the 'real' Debug(AsyncWrap*, ...) functions below, so that
// the FORCE_INLINE flag on them doesn't apply to the contents of this function
// as well.
// We apply COLD_NOINLINE to tell the compiler that it's not worth optimizing
// this function for speed and it should rather focus on keeping it out of
// hot code paths. In particular, we want to keep the string concatenating code
// out of the function containing the original `Debug()` call.
template <typename... Args>
void COLD_NOINLINE UnconditionalAsyncWrapDebug(AsyncWrap* async_wrap,
const char* format,
Args&&... args) {
Debug(async_wrap->env(),
static_cast<DebugCategory>(async_wrap->provider_type()),
async_wrap->diagnostic_name() + " " + format + "\n",
std::forward<Args>(args)...);
}

template <typename... Args>
inline void FORCE_INLINE Debug(AsyncWrap* async_wrap,
const char* format,
Args&&... args) {
DCHECK_NOT_NULL(async_wrap);
DebugCategory cat = static_cast<DebugCategory>(async_wrap->provider_type());
if (!UNLIKELY(async_wrap->env()->enabled_debug_list()->enabled(cat))) return;
UnconditionalAsyncWrapDebug(async_wrap, format, std::forward<Args>(args)...);
}

template <typename... Args>
inline void FORCE_INLINE Debug(AsyncWrap* async_wrap,
const std::string& format,
Args&&... args) {
Debug(async_wrap, format.c_str(), std::forward<Args>(args)...);
}

namespace per_process {

template <typename... Args>
inline void FORCE_INLINE Debug(DebugCategory cat,
const char* format,
Args&&... args) {
Debug(&enabled_debug_list, cat, format, std::forward<Args>(args)...);
}

inline void FORCE_INLINE Debug(DebugCategory cat, const char* message) {
Debug(&enabled_debug_list, cat, message);
}

} // namespace per_process
} // namespace node

#endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
Expand Down
32 changes: 32 additions & 0 deletions src/debug_utils.cc
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#include "debug_utils-inl.h" // NOLINT(build/include)
#include "env-inl.h"
#include "node_internals.h"

#ifdef __POSIX__
#if defined(__linux__)
Expand Down Expand Up @@ -53,6 +54,37 @@
#endif // _WIN32

namespace node {
namespace per_process {
EnabledDebugList enabled_debug_list;
}

void EnabledDebugList::Parse(Environment* env) {
std::string cats;
credentials::SafeGetenv("NODE_DEBUG_NATIVE", &cats, env);
Parse(cats, true);
}

void EnabledDebugList::Parse(const std::string& cats, bool enabled) {
std::string debug_categories = cats;
while (!debug_categories.empty()) {
std::string::size_type comma_pos = debug_categories.find(',');
std::string wanted = ToLower(debug_categories.substr(0, comma_pos));

#define V(name) \
{ \
static const std::string available_category = ToLower(#name); \
if (available_category.find(wanted) != std::string::npos) \
set_enabled(DebugCategory::name, enabled); \
}

DEBUG_CATEGORY_NAMES(V)
#undef V

if (comma_pos == std::string::npos) break;
// Use everything after the `,` as the list for the next iteration.
debug_categories = debug_categories.substr(comma_pos + 1);
}
}

#ifdef __POSIX__
#if HAVE_EXECINFO_H
Expand Down
101 changes: 69 additions & 32 deletions src/debug_utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
#if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS

#include "async_wrap.h"
#include "env.h"

#include <sstream>
#include <string>
Expand All @@ -21,6 +20,7 @@
#endif

namespace node {
class Environment;

template <typename T>
inline std::string ToString(const T& value);
Expand All @@ -36,31 +36,72 @@ template <typename... Args>
inline void FPrintF(FILE* file, const char* format, Args&&... args);
void FWrite(FILE* file, const std::string& str);

// Listing the AsyncWrap provider types first enables us to cast directly
// from a provider type to a debug category.
#define DEBUG_CATEGORY_NAMES(V) \
NODE_ASYNC_PROVIDER_TYPES(V) \
V(INSPECTOR_SERVER) \
V(INSPECTOR_PROFILER) \
V(CODE_CACHE) \
V(WASI)

enum class DebugCategory {
#define V(name) name,
DEBUG_CATEGORY_NAMES(V)
#undef V
CATEGORY_COUNT
};

class EnabledDebugList {
public:
bool enabled(DebugCategory category) const {
DCHECK_GE(static_cast<int>(category), 0);
DCHECK_LT(static_cast<int>(category),
static_cast<int>(DebugCategory::CATEGORY_COUNT));
return enabled_[static_cast<int>(category)];
}

// Uses NODE_DEBUG_NATIVE to initialize the categories. When env is not a
// nullptr, the environment variables set in the Environment are used.
// Otherwise the system environment variables are used.
void Parse(Environment* env);

private:
// Set all categories matching cats to the value of enabled.
void Parse(const std::string& cats, bool enabled);
void set_enabled(DebugCategory category, bool enabled) {
DCHECK_GE(static_cast<int>(category), 0);
DCHECK_LT(static_cast<int>(category),
static_cast<int>(DebugCategory::CATEGORY_COUNT));
enabled_[static_cast<int>(category)] = true;
}

bool enabled_[static_cast<int>(DebugCategory::CATEGORY_COUNT)] = {false};
};

template <typename... Args>
inline void FORCE_INLINE Debug(Environment* env,
inline void FORCE_INLINE Debug(EnabledDebugList* list,
DebugCategory cat,
const char* format,
Args&&... args) {
if (!UNLIKELY(env->debug_enabled(cat)))
return;
FPrintF(stderr, format, std::forward<Args>(args)...);
}
Args&&... args);

inline void FORCE_INLINE Debug(EnabledDebugList* list,
DebugCategory cat,
const char* message);

template <typename... Args>
inline void FORCE_INLINE
Debug(Environment* env, DebugCategory cat, const char* format, Args&&... args);

inline void FORCE_INLINE Debug(Environment* env,
DebugCategory cat,
const char* message) {
if (!UNLIKELY(env->debug_enabled(cat)))
return;
FPrintF(stderr, "%s", message);
}
const char* message);

template <typename... Args>
inline void Debug(Environment* env,
DebugCategory cat,
const std::string& format,
Args&&... args) {
Debug(env, cat, format.c_str(), std::forward<Args>(args)...);
}
Args&&... args);

// Used internally by the 'real' Debug(AsyncWrap*, ...) functions below, so that
// the FORCE_INLINE flag on them doesn't apply to the contents of this function
Expand All @@ -72,31 +113,17 @@ inline void Debug(Environment* env,
template <typename... Args>
void COLD_NOINLINE UnconditionalAsyncWrapDebug(AsyncWrap* async_wrap,
const char* format,
Args&&... args) {
Debug(async_wrap->env(),
static_cast<DebugCategory>(async_wrap->provider_type()),
async_wrap->diagnostic_name() + " " + format + "\n",
std::forward<Args>(args)...);
}
Args&&... args);

template <typename... Args>
inline void FORCE_INLINE Debug(AsyncWrap* async_wrap,
const char* format,
Args&&... args) {
DCHECK_NOT_NULL(async_wrap);
DebugCategory cat =
static_cast<DebugCategory>(async_wrap->provider_type());
if (!UNLIKELY(async_wrap->env()->debug_enabled(cat)))
return;
UnconditionalAsyncWrapDebug(async_wrap, format, std::forward<Args>(args)...);
}
Args&&... args);

template <typename... Args>
inline void FORCE_INLINE Debug(AsyncWrap* async_wrap,
const std::string& format,
Args&&... args) {
Debug(async_wrap, format.c_str(), std::forward<Args>(args)...);
}
Args&&... args);

// Debug helper for inspecting the currently running `node` executable.
class NativeSymbolDebuggingContext {
Expand Down Expand Up @@ -135,6 +162,16 @@ class NativeSymbolDebuggingContext {
void CheckedUvLoopClose(uv_loop_t* loop);
void PrintLibuvHandleInformation(uv_loop_t* loop, FILE* stream);

namespace per_process {
extern EnabledDebugList enabled_debug_list;

template <typename... Args>
inline void FORCE_INLINE Debug(DebugCategory cat,
const char* format,
Args&&... args);

inline void FORCE_INLINE Debug(DebugCategory cat, const char* message);
} // namespace per_process
} // namespace node

#endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
Expand Down
14 changes: 0 additions & 14 deletions src/env-inl.h
Original file line number Diff line number Diff line change
Expand Up @@ -609,20 +609,6 @@ inline void Environment::set_http2_state(
http2_state_ = std::move(buffer);
}

bool Environment::debug_enabled(DebugCategory category) const {
DCHECK_GE(static_cast<int>(category), 0);
DCHECK_LT(static_cast<int>(category),
static_cast<int>(DebugCategory::CATEGORY_COUNT));
return debug_enabled_[static_cast<int>(category)];
}

void Environment::set_debug_enabled(DebugCategory category, bool enabled) {
DCHECK_GE(static_cast<int>(category), 0);
DCHECK_LT(static_cast<int>(category),
static_cast<int>(DebugCategory::CATEGORY_COUNT));
debug_enabled_[static_cast<int>(category)] = enabled;
}

inline AliasedFloat64Array* Environment::fs_stats_field_array() {
return &fs_stats_field_array_;
}
Expand Down
Loading