diff --git a/binding.gyp b/binding.gyp index 1a8bd74..2c1a15e 100644 --- a/binding.gyp +++ b/binding.gyp @@ -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", diff --git a/src/environment_data.cc b/src/environment_data.cc index 8ff7390..176e6a9 100644 --- a/src/environment_data.cc +++ b/src/environment_data.cc @@ -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& 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(new EnvironmentData(isolate, loop)); - xprofiler::AtExit(isolate, AtExit, nullptr); - - return per_process::process_data.environment_data.get(); + registry->Register(isolate, std::unique_ptr( + new EnvironmentData(isolate, loop))); + xprofiler::AtExit(isolate, AtExit, isolate); } EnvironmentData::EnvironmentData(v8::Isolate* isolate, uv_loop_t* loop) @@ -49,16 +58,12 @@ EnvironmentData::EnvironmentData(v8::Isolate* isolate, uv_loop_t* loop) uv_unref(reinterpret_cast(&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(arg); + EnvironmentRegistry* registry = ProcessData::Get()->environment_registry(); + EnvironmentRegistry::NoExitScope scope(registry); + registry->Unregister(isolate); } void EnvironmentData::SendCollectStatistics() { @@ -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(data); std::list requests; @@ -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); @@ -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); diff --git a/src/environment_data.h b/src/environment_data.h index 216ac2d..ec85129 100644 --- a/src/environment_data.h +++ b/src/environment_data.h @@ -29,7 +29,7 @@ class EnvironmentData { static EnvironmentData* GetCurrent(v8::Isolate* isolate); static EnvironmentData* GetCurrent( const Nan::FunctionCallbackInfo& info); - static EnvironmentData* Create(v8::Isolate* isolate); + static void Create(v8::Isolate* isolate); void SendCollectStatistics(); diff --git a/src/environment_registry.cc b/src/environment_registry.cc new file mode 100644 index 0000000..547ac11 --- /dev/null +++ b/src/environment_registry.cc @@ -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 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 diff --git a/src/environment_registry.h b/src/environment_registry.h new file mode 100644 index 0000000..57a683c --- /dev/null +++ b/src/environment_registry.h @@ -0,0 +1,66 @@ +#ifndef XPROFILER_SRC_ENVIRONMENT_REGISTRY_H +#define XPROFILER_SRC_ENVIRONMENT_REGISTRY_H + +#include +#include + +#include "environment_data.h" +#include "nan.h" +#include "xpf_mutex-inl.h" + +namespace xprofiler { + +class EnvironmentRegistry { + using Map = + std::unordered_map>; + + 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 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 */ diff --git a/src/logbypass/log.cc b/src/logbypass/log.cc index 145d6b3..2622f06 100644 --- a/src/logbypass/log.cc +++ b/src/logbypass/log.cc @@ -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" @@ -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& info) { @@ -77,12 +94,11 @@ void RunLogBypass(const FunctionCallbackInfo& info) { Info("init", "logbypass: gc hooks setted."); // init log thread - per_process::process_data.log_by_pass = - std::unique_ptr(new LogByPass()); - per_process::process_data.log_by_pass->StartIfNeeded(); + ProcessData::Get()->log_by_pass = std::unique_ptr(new LogByPass()); + ProcessData::Get()->log_by_pass->StartIfNeeded(); Info("init", "logbypass: log thread created."); info.GetReturnValue().Set(True()); } -} // namespace xprofiler \ No newline at end of file +} // namespace xprofiler diff --git a/src/logbypass/log.h b/src/logbypass/log.h index a432e59..5a2d711 100644 --- a/src/logbypass/log.h +++ b/src/logbypass/log.h @@ -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; diff --git a/src/process_data.cc b/src/process_data.cc new file mode 100644 index 0000000..d566f61 --- /dev/null +++ b/src/process_data.cc @@ -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 diff --git a/src/process_data.h b/src/process_data.h index 80a263a..4cea893 100644 --- a/src/process_data.h +++ b/src/process_data.h @@ -2,6 +2,7 @@ #define XPROFILER_SRC_PROCESS_DATA_H #include "environment_data.h" +#include "environment_registry.h" #include "logbypass/log.h" namespace xprofiler { @@ -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 environment_data; + EnvironmentRegistry* environment_registry() { + return &environment_registry_; + }; std::unique_ptr log_by_pass; -}; -namespace per_process { -extern ProcessData process_data; -} + private: + EnvironmentRegistry environment_registry_; +}; } // namespace xprofiler diff --git a/src/xprofiler.cc b/src/xprofiler.cc index 6d7d19f..058b8ca 100644 --- a/src/xprofiler.cc +++ b/src/xprofiler.cc @@ -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();