11
2- #include < node_api.h>
3-
42#include < assert.h>
53#include < math.h>
4+ #include < node_api.h>
65#include < string.h>
6+ #include < uv.h>
7+ #include < v8-profiler.h>
8+ #include < v8.h>
79
810#include < functional>
911#include < string>
1012#include < unordered_map>
1113
12- #include < v8-profiler.h>
13- #include < v8.h>
14-
15- #include < uv.h>
16-
1714#define FORMAT_SAMPLED 2
1815#define FORMAT_RAW 1
1916
2623#endif
2724
2825static const uint8_t kMaxStackDepth (128 );
29- static const float kSamplingFrequency (99.0 ); // 99 to avoid lockstep sampling
26+ static const float kSamplingFrequency (99.0 ); // 99 to avoid lockstep sampling
3027static const float kSamplingHz (1 / kSamplingFrequency );
3128static const int kSamplingInterval (kSamplingHz * 1e6 );
32- static const v8::CpuProfilingNamingMode
33- kNamingMode ( v8::CpuProfilingNamingMode::kDebugNaming );
34- static const v8::CpuProfilingLoggingMode
35- kDefaultLoggingMode ( v8::CpuProfilingLoggingMode::kEagerLogging );
29+ static const v8::CpuProfilingNamingMode kNamingMode (
30+ v8::CpuProfilingNamingMode::kDebugNaming );
31+ static const v8::CpuProfilingLoggingMode kDefaultLoggingMode (
32+ v8::CpuProfilingLoggingMode::kEagerLogging );
3633
3734// Allow users to override the default logging mode via env variable. This is
3835// useful because sometimes the flow of the profiled program can be to execute
@@ -54,8 +51,7 @@ v8::CpuProfilingLoggingMode GetLoggingMode() {
5451 // other times it'll likely be set to lazy as eager is the default
5552 if (strcmp (logging_mode, kLazyLoggingMode ) == 0 ) {
5653 return v8::CpuProfilingLoggingMode::kLazyLogging ;
57- }
58- else if (strcmp (logging_mode, kEagerLoggingMode ) == 0 ) {
54+ } else if (strcmp (logging_mode, kEagerLoggingMode ) == 0 ) {
5955 return v8::CpuProfilingLoggingMode::kEagerLogging ;
6056 }
6157
@@ -72,7 +68,7 @@ enum class ProfileStatus {
7268};
7369
7470class MeasurementsTicker {
75- private:
71+ private:
7672 uv_timer_t timer;
7773 uint64_t period_ms;
7874 std::unordered_map<std::string,
@@ -84,7 +80,7 @@ class MeasurementsTicker {
8480 v8::HeapStatistics heap_stats;
8581 uv_cpu_info_t cpu_stats;
8682
87- public:
83+ public:
8884 MeasurementsTicker (uv_loop_t *loop)
8985 : period_ms(100 ), isolate(v8::Isolate::GetCurrent()) {
9086 uv_timer_init (loop, &timer);
@@ -109,6 +105,11 @@ class MeasurementsTicker {
109105 const std::function<bool (uint64_t , double )> &cb);
110106
111107 size_t listener_count ();
108+
109+ ~MeasurementsTicker () {
110+ uv_timer_stop (&timer);
111+ uv_close (reinterpret_cast <uv_handle_t *>(&timer), nullptr );
112+ }
112113};
113114
114115size_t MeasurementsTicker::listener_count () {
@@ -222,7 +223,7 @@ void MeasurementsTicker::remove_cpu_listener(
222223};
223224
224225class Profiler {
225- public:
226+ public:
226227 std::unordered_map<std::string, SentryProfile *> active_profiles;
227228
228229 MeasurementsTicker measurements_ticker;
@@ -231,15 +232,11 @@ class Profiler {
231232 explicit Profiler (const napi_env &env, v8::Isolate *isolate)
232233 : measurements_ticker(uv_default_loop()),
233234 cpu_profiler(
234- v8::CpuProfiler::New (isolate, kNamingMode , GetLoggingMode())) {
235- napi_add_env_cleanup_hook (env, DeleteInstance, this );
236- }
237-
238- static void DeleteInstance (void *data);
235+ v8::CpuProfiler::New (isolate, kNamingMode , GetLoggingMode())) {}
239236};
240237
241238class SentryProfile {
242- private:
239+ private:
243240 uint64_t started_at;
244241 uint16_t heap_write_index = 0 ;
245242 uint16_t cpu_write_index = 0 ;
@@ -256,7 +253,7 @@ class SentryProfile {
256253 ProfileStatus status = ProfileStatus::kNotStarted ;
257254 std::string id;
258255
259- public:
256+ public:
260257 explicit SentryProfile (const char *id)
261258 : started_at(uv_hrtime()),
262259 memory_sampler_cb([this ](uint64_t ts, v8::HeapStatistics &stats) {
@@ -288,7 +285,8 @@ class SentryProfile {
288285 return false ;
289286 }),
290287
291- status (ProfileStatus::kNotStarted ), id(id) {
288+ status (ProfileStatus::kNotStarted ),
289+ id (id) {
292290 heap_stats_ts.reserve (300 );
293291 heap_stats_usage.reserve (300 );
294292 cpu_stats_ts.reserve (300 );
@@ -335,21 +333,11 @@ static void CleanupSentryProfile(Profiler *profiler,
335333 return ;
336334 }
337335
336+ sentry_profile->Stop (profiler);
338337 profiler->active_profiles .erase (profile_id);
339338 delete sentry_profile;
340339};
341340
342- void Profiler::DeleteInstance (void *data) {
343- Profiler *profiler = static_cast <Profiler *>(data);
344-
345- for (auto &profile : profiler->active_profiles ) {
346- CleanupSentryProfile (profiler, profile.second , profile.first );
347- }
348-
349- profiler->cpu_profiler ->Dispose ();
350- delete profiler;
351- }
352-
353341v8::CpuProfile *SentryProfile::Stop (Profiler *profiler) {
354342 // Stop the CPU Profiler
355343 v8::CpuProfile *profile = profiler->cpu_profiler ->StopProfiling (
@@ -470,10 +458,10 @@ static napi_value GetFrameModuleWrapped(napi_env env, napi_callback_info info) {
470458 return napi_module;
471459}
472460
473- napi_value
474- CreateFrameNode ( const napi_env &env, const v8::CpuProfileNode &node,
475- std::unordered_map<std::string, std::string> &module_cache,
476- napi_value &resources) {
461+ napi_value CreateFrameNode (
462+ const napi_env &env, const v8::CpuProfileNode &node,
463+ std::unordered_map<std::string, std::string> &module_cache,
464+ napi_value &resources) {
477465 napi_value js_node;
478466 napi_create_object (env, &js_node);
479467
@@ -681,11 +669,10 @@ static void GetSamples(const napi_env &env, const v8::CpuProfile *profile,
681669 }
682670}
683671
684- static napi_value
685- TranslateMeasurementsDouble (const napi_env &env, const char *unit,
686- const uint16_t size,
687- const std::vector<double > &values,
688- const std::vector<uint64_t > ×tamps) {
672+ static napi_value TranslateMeasurementsDouble (
673+ const napi_env &env, const char *unit, const uint16_t size,
674+ const std::vector<double > &values,
675+ const std::vector<uint64_t > ×tamps) {
689676 if (size > values.size () || size > timestamps.size ()) {
690677 napi_throw_range_error (env, " NAPI_ERROR" ,
691678 " CPU measurement size is larger than the number of "
@@ -736,10 +723,10 @@ TranslateMeasurementsDouble(const napi_env &env, const char *unit,
736723 return measurement;
737724}
738725
739- static napi_value
740- TranslateMeasurements ( const napi_env &env, const char *unit,
741- const uint16_t size, const std::vector<uint64_t > &values,
742- const std::vector<uint64_t > ×tamps) {
726+ static napi_value TranslateMeasurements (
727+ const napi_env &env, const char *unit, const uint16_t size ,
728+ const std::vector<uint64_t > &values,
729+ const std::vector<uint64_t > ×tamps) {
743730 if (size > values.size () || size > timestamps.size ()) {
744731 napi_throw_range_error (env, " NAPI_ERROR" ,
745732 " Memory measurement size is larger than the number "
@@ -1049,6 +1036,26 @@ static napi_value StopProfiling(napi_env env, napi_callback_info info) {
10491036 return js_profile;
10501037};
10511038
1039+ void FreeAddonData (napi_env env, void *data, void *hint) {
1040+ Profiler *profiler = static_cast <Profiler *>(data);
1041+
1042+ if (profiler == nullptr ) {
1043+ return ;
1044+ }
1045+
1046+ if (!profiler->active_profiles .empty ()) {
1047+ for (auto &profile : profiler->active_profiles ) {
1048+ CleanupSentryProfile (profiler, profile.second , profile.first );
1049+ }
1050+ }
1051+
1052+ if (profiler->cpu_profiler != nullptr ) {
1053+ profiler->cpu_profiler ->Dispose ();
1054+ }
1055+
1056+ delete profiler;
1057+ }
1058+
10521059napi_value Init (napi_env env, napi_value exports) {
10531060 v8::Isolate *isolate = v8::Isolate::GetCurrent ();
10541061
@@ -1060,22 +1067,14 @@ napi_value Init(napi_env env, napi_value exports) {
10601067
10611068 Profiler *profiler = new Profiler (env, isolate);
10621069
1063- if (napi_set_instance_data (env, profiler, NULL , NULL ) != napi_ok) {
1070+ if (napi_set_instance_data (env, profiler, FreeAddonData , NULL ) != napi_ok) {
10641071 napi_throw_error (env, nullptr , " Failed to set instance data for profiler." );
10651072 return NULL ;
10661073 }
10671074
1068- napi_value external;
1069- if (napi_create_external (env, profiler, nullptr , nullptr , &external) !=
1070- napi_ok) {
1071- napi_throw_error (env, nullptr ,
1072- " Failed to create external for profiler instance." );
1073- return NULL ;
1074- }
1075-
10761075 napi_value start_profiling;
10771076 if (napi_create_function (env, " startProfiling" , NAPI_AUTO_LENGTH,
1078- StartProfiling, external ,
1077+ StartProfiling, exports ,
10791078 &start_profiling) != napi_ok) {
10801079 napi_throw_error (env, nullptr , " Failed to create startProfiling function." );
10811080 return NULL ;
@@ -1090,7 +1089,7 @@ napi_value Init(napi_env env, napi_value exports) {
10901089
10911090 napi_value stop_profiling;
10921091 if (napi_create_function (env, " stopProfiling" , NAPI_AUTO_LENGTH,
1093- StopProfiling, external ,
1092+ StopProfiling, exports ,
10941093 &stop_profiling) != napi_ok) {
10951094 napi_throw_error (env, nullptr , " Failed to create stopProfiling function." );
10961095 return NULL ;
@@ -1105,7 +1104,7 @@ napi_value Init(napi_env env, napi_value exports) {
11051104
11061105 napi_value get_frame_module;
11071106 if (napi_create_function (env, " getFrameModule" , NAPI_AUTO_LENGTH,
1108- GetFrameModuleWrapped, external ,
1107+ GetFrameModuleWrapped, exports ,
11091108 &get_frame_module) != napi_ok) {
11101109 napi_throw_error (env, nullptr , " Failed to create getFrameModule function." );
11111110 return NULL ;
0 commit comments