Skip to content

Commit

Permalink
feat: environment registry
Browse files Browse the repository at this point in the history
PR-URL: #147
Reviewed-BY: hyj1991 <[email protected]>
  • Loading branch information
legendecas authored and hyj1991 committed Mar 19, 2022
1 parent 88fc7ed commit c114f45
Show file tree
Hide file tree
Showing 10 changed files with 200 additions and 52 deletions.
2 changes: 2 additions & 0 deletions binding.gyp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
"win_delay_load_hook": "false",
"sources": [
"src/environment_data.cc",
"src/environment_registry.cc",
"src/process_data.cc",
"src/xpf_thread.cc",
"src/xprofiler.cc",
"src/configure.cc",
Expand Down
50 changes: 29 additions & 21 deletions src/environment_data.cc
Original file line number Diff line number Diff line change
Expand Up @@ -11,34 +11,43 @@
namespace xprofiler {
using v8::Isolate;

// static
EnvironmentData* EnvironmentData::GetCurrent() {
// TODO(legendecas): environment registry.
CHECK_NE(per_process::process_data.environment_data, nullptr);
return per_process::process_data.environment_data.get();
EnvironmentRegistry* registry = ProcessData::Get()->environment_registry();
EnvironmentRegistry::NoExitScope scope(registry);

CHECK_NE(registry->begin(), registry->end());
return *registry->begin();
}

// static
EnvironmentData* EnvironmentData::GetCurrent(v8::Isolate* isolate) {
return EnvironmentData::GetCurrent();
EnvironmentRegistry* registry = ProcessData::Get()->environment_registry();
EnvironmentRegistry::NoExitScope scope(registry);
return registry->Get(isolate);
}

// static
EnvironmentData* EnvironmentData::GetCurrent(
const Nan::FunctionCallbackInfo<v8::Value>& info) {
return EnvironmentData::GetCurrent(info.GetIsolate());
}

EnvironmentData* EnvironmentData::Create(v8::Isolate* isolate) {
// TODO(legendecas): environment registry.
CHECK_EQ(per_process::process_data.environment_data, nullptr);
// static
void EnvironmentData::Create(v8::Isolate* isolate) {
EnvironmentRegistry* registry = ProcessData::Get()->environment_registry();
EnvironmentRegistry::NoExitScope no_exit(registry);

// TODO(legendecas): context awareness support.
CHECK_EQ(registry->begin(), registry->end());

HandleScope scope(isolate);
uv_loop_t* loop = node::GetCurrentEventLoop(isolate);
CHECK_NOT_NULL(loop);

per_process::process_data.environment_data =
std::unique_ptr<EnvironmentData>(new EnvironmentData(isolate, loop));
xprofiler::AtExit(isolate, AtExit, nullptr);

return per_process::process_data.environment_data.get();
registry->Register(isolate, std::unique_ptr<EnvironmentData>(
new EnvironmentData(isolate, loop)));
xprofiler::AtExit(isolate, AtExit, isolate);
}

EnvironmentData::EnvironmentData(v8::Isolate* isolate, uv_loop_t* loop)
Expand All @@ -49,16 +58,12 @@ EnvironmentData::EnvironmentData(v8::Isolate* isolate, uv_loop_t* loop)
uv_unref(reinterpret_cast<uv_handle_t*>(&statistics_async_));
}

// static
void EnvironmentData::AtExit(void* arg) {
// TODO(legendecas): environment registry.
// The log_by_pass thread should not be bound to a single environment data.
// For now we just destroy the log_by_pass thread since this is the last env.
if (per_process::process_data.log_by_pass != nullptr) {
per_process::process_data.log_by_pass->Join();
per_process::process_data.log_by_pass.reset();
}
// TODO: issue https://github.com/X-Profiler/xprofiler/runs/5611225669?check_suite_focus=true
// per_process::process_data.environment_data.reset();
Isolate* isolate = reinterpret_cast<Isolate*>(arg);
EnvironmentRegistry* registry = ProcessData::Get()->environment_registry();
EnvironmentRegistry::NoExitScope scope(registry);
registry->Unregister(isolate);
}

void EnvironmentData::SendCollectStatistics() {
Expand All @@ -74,6 +79,7 @@ void EnvironmentData::RequestInterrupt(InterruptCallback interrupt) {
uv_async_send(&interrupt_async_);
}

// static
void EnvironmentData::InterruptBusyCallback(v8::Isolate* isolate, void* data) {
EnvironmentData* env_data = static_cast<EnvironmentData*>(data);
std::list<InterruptCallback> requests;
Expand All @@ -87,6 +93,7 @@ void EnvironmentData::InterruptBusyCallback(v8::Isolate* isolate, void* data) {
}
}

// static
void EnvironmentData::InterruptIdleCallback(uv_async_t* handle) {
EnvironmentData* env_data =
ContainerOf(&EnvironmentData::interrupt_async_, handle);
Expand All @@ -101,6 +108,7 @@ void EnvironmentData::InterruptIdleCallback(uv_async_t* handle) {
}
}

// static
void EnvironmentData::CollectStatistics(uv_async_t* handle) {
EnvironmentData* env_data =
ContainerOf(&EnvironmentData::statistics_async_, handle);
Expand Down
2 changes: 1 addition & 1 deletion src/environment_data.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ class EnvironmentData {
static EnvironmentData* GetCurrent(v8::Isolate* isolate);
static EnvironmentData* GetCurrent(
const Nan::FunctionCallbackInfo<v8::Value>& info);
static EnvironmentData* Create(v8::Isolate* isolate);
static void Create(v8::Isolate* isolate);

void SendCollectStatistics();

Expand Down
43 changes: 43 additions & 0 deletions src/environment_registry.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
#include "environment_registry.h"

namespace xprofiler {

EnvironmentRegistry::NoExitScope::NoExitScope(EnvironmentRegistry* registry)
: registry_(registry), lock_(registry->mutex_) {
registry_->disallow_exit_ = true;
}

EnvironmentRegistry::NoExitScope::~NoExitScope() {
registry_->disallow_exit_ = false;
}

void EnvironmentRegistry::Register(v8::Isolate* isolate,
std::unique_ptr<EnvironmentData> env) {
CHECK(disallow_exit_);
map_.emplace(isolate, std::move(env));
}

void EnvironmentRegistry::Unregister(v8::Isolate* isolate) {
CHECK(disallow_exit_);
CHECK_NE(map_.find(isolate), map_.end());
map_.erase(isolate);
}

EnvironmentData* EnvironmentRegistry::Get(v8::Isolate* isolate) {
CHECK(disallow_exit_);
auto it = map_.find(isolate);
CHECK_NE(it, map_.end());
return it->second.get();
}

EnvironmentRegistry::Iterator EnvironmentRegistry::begin() {
CHECK(disallow_exit_);
return Iterator(map_.begin());
}

EnvironmentRegistry::Iterator EnvironmentRegistry::end() {
CHECK(disallow_exit_);
return Iterator(map_.end());
}

} // namespace xprofiler
66 changes: 66 additions & 0 deletions src/environment_registry.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
#ifndef XPROFILER_SRC_ENVIRONMENT_REGISTRY_H
#define XPROFILER_SRC_ENVIRONMENT_REGISTRY_H

#include <memory>
#include <unordered_map>

#include "environment_data.h"
#include "nan.h"
#include "xpf_mutex-inl.h"

namespace xprofiler {

class EnvironmentRegistry {
using Map =
std::unordered_map<v8::Isolate*, std::unique_ptr<EnvironmentData>>;

public:
class NoExitScope {
public:
explicit NoExitScope(EnvironmentRegistry* registry);
NoExitScope(const NoExitScope& other) = delete;
~NoExitScope();

private:
EnvironmentRegistry* registry_;
Mutex::ScopedLock lock_;
};

class Iterator {
public:
EnvironmentData* operator*() { return it_->second.get(); };
bool operator==(const Iterator& other) { return it_ == other.it_; };
bool operator==(Iterator& other) { return it_ == other.it_; };
bool operator!=(const Iterator& other) { return it_ != other.it_; };
bool operator!=(Iterator& other) { return it_ != other.it_; };

Iterator operator++() { return Iterator(it_++); }

private:
friend EnvironmentRegistry;
explicit Iterator(Map::iterator it) : it_(it){};
Map::iterator it_;
};

EnvironmentRegistry(){};
// Disallow copy
EnvironmentRegistry(const EnvironmentRegistry& other) = delete;

void Register(v8::Isolate* isolate, std::unique_ptr<EnvironmentData> env);
void Unregister(v8::Isolate* isolate);
EnvironmentData* Get(v8::Isolate* isolate);

Iterator begin();
Iterator end();

private:
friend NoExitScope;

bool disallow_exit_ = false;
Mutex mutex_;
Map map_;
};

} // namespace xprofiler

#endif /* XPROFILER_SRC_ENVIRONMENT_REGISTRY_H */
54 changes: 35 additions & 19 deletions src/logbypass/log.cc
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include "configure-inl.h"
#include "cpu.h"
#include "environment_data.h"
#include "environment_registry.h"
#include "gc.h"
#include "heap.h"
#include "http.h"
Expand Down Expand Up @@ -39,36 +40,52 @@ void LogByPass::OnCpuInterval(uv_timer_t* handle) {
SetNowCpuUsage();
}

// static
void LogByPass::OnLogInterval(uv_timer_t* handle) {
LogByPass* that = ContainerOf(&LogByPass::log_interval_, handle);
EnvironmentData* env_data = EnvironmentData::GetCurrent();
if (!that->next_log_) {
env_data->SendCollectStatistics();
that->next_log_ = true;
that->SendCollectStatistics();
CHECK_EQ(0,
uv_timer_start(&that->log_interval_, OnLogInterval, 1000, false));
return;
}
that->next_log_ = false;
bool log_format_alinode = GetFormatAsAlinode();
that->CollectStatistics();
CHECK_EQ(0, uv_timer_start(&that->log_interval_, OnLogInterval,
GetLogInterval() * 1000, false));
}

// write cpu info
WriteCpuUsageInPeriod(log_format_alinode);
void LogByPass::SendCollectStatistics() {
EnvironmentRegistry* registry = ProcessData::Get()->environment_registry();
EnvironmentRegistry::NoExitScope scope(registry);

// write heap memory info
WriteMemoryInfoToLog(env_data, log_format_alinode);
for (EnvironmentData* env_data : *registry) {
env_data->SendCollectStatistics();
}
}

// write gc status
WriteGcStatusToLog(env_data, log_format_alinode);
void LogByPass::CollectStatistics() {
EnvironmentRegistry* registry = ProcessData::Get()->environment_registry();
EnvironmentRegistry::NoExitScope scope(registry);
bool log_format_alinode = GetFormatAsAlinode();

// write libuv handle info
WriteLibuvHandleInfoToLog(env_data, log_format_alinode);
for (EnvironmentData* env_data : *registry) {
// write cpu info
WriteCpuUsageInPeriod(log_format_alinode);

// write http status
WriteHttpStatus(env_data, log_format_alinode, GetPatchHttpTimeout());
// write heap memory info
WriteMemoryInfoToLog(env_data, log_format_alinode);

CHECK_EQ(0, uv_timer_start(&that->log_interval_, OnLogInterval,
GetLogInterval() * 1000, false));
// write gc status
WriteGcStatusToLog(env_data, log_format_alinode);

// write libuv handle info
WriteLibuvHandleInfoToLog(env_data, log_format_alinode);

// write http status
WriteHttpStatus(env_data, log_format_alinode, GetPatchHttpTimeout());
}
}

void RunLogBypass(const FunctionCallbackInfo<Value>& info) {
Expand All @@ -77,12 +94,11 @@ void RunLogBypass(const FunctionCallbackInfo<Value>& info) {
Info("init", "logbypass: gc hooks setted.");

// init log thread
per_process::process_data.log_by_pass =
std::unique_ptr<LogByPass>(new LogByPass());
per_process::process_data.log_by_pass->StartIfNeeded();
ProcessData::Get()->log_by_pass = std::unique_ptr<LogByPass>(new LogByPass());
ProcessData::Get()->log_by_pass->StartIfNeeded();
Info("init", "logbypass: log thread created.");

info.GetReturnValue().Set(True());
}

} // namespace xprofiler
} // namespace xprofiler
4 changes: 4 additions & 0 deletions src/logbypass/log.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ class LogByPass final : public XpfThread {
private:
static void OnCpuInterval(uv_timer_t* handle);
static void OnLogInterval(uv_timer_t* handle);

void SendCollectStatistics();
void CollectStatistics();

uv_timer_t cpu_interval_;
uv_timer_t log_interval_;
bool next_log_ = false;
Expand Down
11 changes: 11 additions & 0 deletions src/process_data.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#include "process_data.h"

namespace xprofiler {

namespace per_process {
ProcessData process_data;
}

ProcessData* ProcessData::Get() { return &per_process::process_data; }

} // namespace xprofiler
16 changes: 9 additions & 7 deletions src/process_data.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#define XPROFILER_SRC_PROCESS_DATA_H

#include "environment_data.h"
#include "environment_registry.h"
#include "logbypass/log.h"

namespace xprofiler {
Expand All @@ -12,24 +13,25 @@ namespace xprofiler {
// Do our best course to destruct per_process slots in an expected order.
class ProcessData {
public:
static ProcessData* Get();

ProcessData(){};
~ProcessData() {
if (log_by_pass != nullptr) {
log_by_pass->Join();
}
};

// Disallow copy;
ProcessData(const ProcessData& other) = delete;

// TODO(legendecas): environment registry.
std::unique_ptr<EnvironmentData> environment_data;
EnvironmentRegistry* environment_registry() {
return &environment_registry_;
};
std::unique_ptr<LogByPass> log_by_pass;
};

namespace per_process {
extern ProcessData process_data;
}
private:
EnvironmentRegistry environment_registry_;
};

} // namespace xprofiler

Expand Down
4 changes: 0 additions & 4 deletions src/xprofiler.cc
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,6 @@ using v8::FunctionTemplate;
using v8::Isolate;
using v8::String;

namespace per_process {
ProcessData process_data;
}

NODE_C_CTOR(Main) {
// init global variables
InitOnceLoadTime();
Expand Down

0 comments on commit c114f45

Please sign in to comment.