@sentry/profiling-node 8.7.0 → 8.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bindings/cpu_profiler.cc +174 -73
- package/lib/cjs/index.js +479 -154
- package/lib/cjs/index.js.map +1 -1
- package/lib/esm/index.js +478 -154
- package/lib/esm/index.js.map +1 -1
- package/lib/sentry_cpu_profiler-darwin-arm64-108.node +0 -0
- package/lib/sentry_cpu_profiler-darwin-arm64-115.node +0 -0
- package/lib/sentry_cpu_profiler-darwin-arm64-127.node +0 -0
- package/lib/sentry_cpu_profiler-darwin-arm64-93.node +0 -0
- package/lib/sentry_cpu_profiler-darwin-x64-108.node +0 -0
- package/lib/sentry_cpu_profiler-darwin-x64-115.node +0 -0
- package/lib/sentry_cpu_profiler-darwin-x64-127.node +0 -0
- package/lib/sentry_cpu_profiler-darwin-x64-93.node +0 -0
- package/lib/sentry_cpu_profiler-linux-arm64-glibc-108.node +0 -0
- package/lib/sentry_cpu_profiler-linux-arm64-glibc-115.node +0 -0
- package/lib/sentry_cpu_profiler-linux-arm64-glibc-127.node +0 -0
- package/lib/sentry_cpu_profiler-linux-arm64-glibc-93.node +0 -0
- package/lib/sentry_cpu_profiler-linux-arm64-musl-108.node +0 -0
- package/lib/sentry_cpu_profiler-linux-arm64-musl-115.node +0 -0
- package/lib/sentry_cpu_profiler-linux-arm64-musl-127.node +0 -0
- package/lib/sentry_cpu_profiler-linux-arm64-musl-93.node +0 -0
- package/lib/sentry_cpu_profiler-linux-x64-glibc-108.node +0 -0
- package/lib/sentry_cpu_profiler-linux-x64-glibc-115.node +0 -0
- package/lib/sentry_cpu_profiler-linux-x64-glibc-127.node +0 -0
- package/lib/sentry_cpu_profiler-linux-x64-glibc-93.node +0 -0
- package/lib/sentry_cpu_profiler-linux-x64-musl-108.node +0 -0
- package/lib/sentry_cpu_profiler-linux-x64-musl-115.node +0 -0
- package/lib/sentry_cpu_profiler-linux-x64-musl-127.node +0 -0
- package/lib/sentry_cpu_profiler-linux-x64-musl-93.node +0 -0
- package/lib/sentry_cpu_profiler-win32-x64-108.node +0 -0
- package/lib/sentry_cpu_profiler-win32-x64-115.node +0 -0
- package/lib/sentry_cpu_profiler-win32-x64-127.node +0 -0
- package/lib/sentry_cpu_profiler-win32-x64-93.node +0 -0
- package/lib/types/profiling-node/src/cpu_profiler.d.ts +16 -0
- package/lib/types/profiling-node/src/cpu_profiler.d.ts.map +1 -0
- package/lib/types/profiling-node/src/debug-build.d.ts.map +1 -0
- package/lib/types/profiling-node/src/index.d.ts.map +1 -0
- package/lib/types/profiling-node/src/integration.d.ts +57 -0
- package/lib/types/profiling-node/src/integration.d.ts.map +1 -0
- package/lib/types/profiling-node/src/nodeVersion.d.ts.map +1 -0
- package/lib/types/{spanProfileUtils.d.ts → profiling-node/src/spanProfileUtils.d.ts} +2 -2
- package/lib/types/profiling-node/src/spanProfileUtils.d.ts.map +1 -0
- package/lib/types/profiling-node/src/types.d.ts +60 -0
- package/lib/types/profiling-node/src/types.d.ts.map +1 -0
- package/lib/types/{utils.d.ts → profiling-node/src/utils.d.ts} +30 -4
- package/lib/types/profiling-node/src/utils.d.ts.map +1 -0
- package/lib/types/types/src/debugMeta.d.ts +28 -0
- package/lib/types/types/src/debugMeta.d.ts.map +1 -0
- package/lib/types/types/src/measurement.d.ts +24 -0
- package/lib/types/types/src/measurement.d.ts.map +1 -0
- package/lib/types/types/src/profiling.d.ts +126 -0
- package/lib/types/types/src/profiling.d.ts.map +1 -0
- package/lib/types-ts3.8/profiling-node/src/cpu_profiler.d.ts +16 -0
- package/lib/types-ts3.8/profiling-node/src/integration.d.ts +57 -0
- package/lib/types-ts3.8/{spanProfileUtils.d.ts → profiling-node/src/spanProfileUtils.d.ts} +2 -2
- package/lib/types-ts3.8/profiling-node/src/types.d.ts +60 -0
- package/lib/types-ts3.8/{utils.d.ts → profiling-node/src/utils.d.ts} +30 -4
- package/lib/types-ts3.8/types/src/debugMeta.d.ts +28 -0
- package/lib/types-ts3.8/types/src/measurement.d.ts +24 -0
- package/lib/types-ts3.8/types/src/profiling.d.ts +126 -0
- package/package.json +5 -5
- package/lib/types/cpu_profiler.d.ts +0 -10
- package/lib/types/cpu_profiler.d.ts.map +0 -1
- package/lib/types/debug-build.d.ts.map +0 -1
- package/lib/types/index.d.ts.map +0 -1
- package/lib/types/integration.d.ts +0 -14
- package/lib/types/integration.d.ts.map +0 -1
- package/lib/types/nodeVersion.d.ts.map +0 -1
- package/lib/types/spanProfileUtils.d.ts.map +0 -1
- package/lib/types/types.d.ts +0 -100
- package/lib/types/types.d.ts.map +0 -1
- package/lib/types/utils.d.ts.map +0 -1
- package/lib/types-ts3.8/cpu_profiler.d.ts +0 -10
- package/lib/types-ts3.8/integration.d.ts +0 -14
- package/lib/types-ts3.8/types.d.ts +0 -100
- /package/lib/types/{debug-build.d.ts → profiling-node/src/debug-build.d.ts} +0 -0
- /package/lib/types/{index.d.ts → profiling-node/src/index.d.ts} +0 -0
- /package/lib/types/{nodeVersion.d.ts → profiling-node/src/nodeVersion.d.ts} +0 -0
- /package/lib/types-ts3.8/{debug-build.d.ts → profiling-node/src/debug-build.d.ts} +0 -0
- /package/lib/types-ts3.8/{index.d.ts → profiling-node/src/index.d.ts} +0 -0
- /package/lib/types-ts3.8/{nodeVersion.d.ts → profiling-node/src/nodeVersion.d.ts} +0 -0
package/bindings/cpu_profiler.cc
CHANGED
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
#include <v8-profiler.h>
|
|
11
11
|
#include <v8.h>
|
|
12
12
|
|
|
13
|
+
#include <chrono>
|
|
13
14
|
#include <functional>
|
|
14
15
|
#include <string>
|
|
15
16
|
#include <unordered_map>
|
|
@@ -23,6 +24,10 @@ static const v8::CpuProfilingNamingMode
|
|
|
23
24
|
static const v8::CpuProfilingLoggingMode
|
|
24
25
|
kDefaultLoggingMode(v8::CpuProfilingLoggingMode::kEagerLogging);
|
|
25
26
|
|
|
27
|
+
enum ProfileFormat {
|
|
28
|
+
kFormatThread = 0,
|
|
29
|
+
kFormatChunk = 1,
|
|
30
|
+
};
|
|
26
31
|
// Allow users to override the default logging mode via env variable. This is
|
|
27
32
|
// useful because sometimes the flow of the profiled program can be to execute
|
|
28
33
|
// many sequential transaction - in that case, it may be preferable to set eager
|
|
@@ -50,6 +55,12 @@ v8::CpuProfilingLoggingMode GetLoggingMode() {
|
|
|
50
55
|
return kDefaultLoggingMode;
|
|
51
56
|
}
|
|
52
57
|
|
|
58
|
+
uint64_t timestamp_milliseconds() {
|
|
59
|
+
return std::chrono::duration_cast<std::chrono::milliseconds>(
|
|
60
|
+
std::chrono::system_clock::now().time_since_epoch())
|
|
61
|
+
.count();
|
|
62
|
+
}
|
|
63
|
+
|
|
53
64
|
class SentryProfile;
|
|
54
65
|
class Profiler;
|
|
55
66
|
|
|
@@ -76,7 +87,8 @@ public:
|
|
|
76
87
|
MeasurementsTicker(uv_loop_t *loop)
|
|
77
88
|
: period_ms(100), isolate(v8::Isolate::GetCurrent()) {
|
|
78
89
|
uv_timer_init(loop, &timer);
|
|
79
|
-
timer
|
|
90
|
+
uv_handle_set_data(reinterpret_cast<uv_handle_t *>(&timer), this);
|
|
91
|
+
uv_unref(reinterpret_cast<uv_handle_t *>(&timer));
|
|
80
92
|
}
|
|
81
93
|
|
|
82
94
|
static void ticker(uv_timer_t *);
|
|
@@ -196,6 +208,10 @@ void MeasurementsTicker::cpu_callback() {
|
|
|
196
208
|
};
|
|
197
209
|
|
|
198
210
|
void MeasurementsTicker::ticker(uv_timer_t *handle) {
|
|
211
|
+
if (handle == nullptr) {
|
|
212
|
+
return;
|
|
213
|
+
}
|
|
214
|
+
|
|
199
215
|
MeasurementsTicker *self = static_cast<MeasurementsTicker *>(handle->data);
|
|
200
216
|
self->heap_callback();
|
|
201
217
|
self->cpu_callback();
|
|
@@ -236,6 +252,7 @@ public:
|
|
|
236
252
|
class SentryProfile {
|
|
237
253
|
private:
|
|
238
254
|
uint64_t started_at;
|
|
255
|
+
uint64_t timestamp;
|
|
239
256
|
uint16_t heap_write_index = 0;
|
|
240
257
|
uint16_t cpu_write_index = 0;
|
|
241
258
|
|
|
@@ -253,7 +270,7 @@ private:
|
|
|
253
270
|
|
|
254
271
|
public:
|
|
255
272
|
explicit SentryProfile(const char *id)
|
|
256
|
-
: started_at(uv_hrtime()),
|
|
273
|
+
: started_at(uv_hrtime()), timestamp(timestamp_milliseconds()),
|
|
257
274
|
memory_sampler_cb([this](uint64_t ts, v8::HeapStatistics &stats) {
|
|
258
275
|
if ((heap_write_index >= heap_stats_ts.capacity()) ||
|
|
259
276
|
heap_write_index >= heap_stats_usage.capacity()) {
|
|
@@ -297,6 +314,7 @@ public:
|
|
|
297
314
|
const std::vector<uint64_t> &cpu_usage_timestamps() const;
|
|
298
315
|
const std::vector<double> &cpu_usage_values() const;
|
|
299
316
|
const uint16_t &cpu_usage_write_index() const;
|
|
317
|
+
const uint64_t &profile_start_timestamp() const;
|
|
300
318
|
|
|
301
319
|
void Start(Profiler *profiler);
|
|
302
320
|
v8::CpuProfile *Stop(Profiler *profiler);
|
|
@@ -309,6 +327,7 @@ void SentryProfile::Start(Profiler *profiler) {
|
|
|
309
327
|
.ToLocalChecked();
|
|
310
328
|
|
|
311
329
|
started_at = uv_hrtime();
|
|
330
|
+
timestamp = timestamp_milliseconds();
|
|
312
331
|
|
|
313
332
|
// Initialize the CPU Profiler
|
|
314
333
|
profiler->cpu_profiler->StartProfiling(
|
|
@@ -323,18 +342,6 @@ void SentryProfile::Start(Profiler *profiler) {
|
|
|
323
342
|
status = ProfileStatus::kStarted;
|
|
324
343
|
}
|
|
325
344
|
|
|
326
|
-
static void CleanupSentryProfile(Profiler *profiler,
|
|
327
|
-
SentryProfile *sentry_profile,
|
|
328
|
-
const std::string &profile_id) {
|
|
329
|
-
if (sentry_profile == nullptr) {
|
|
330
|
-
return;
|
|
331
|
-
}
|
|
332
|
-
|
|
333
|
-
sentry_profile->Stop(profiler);
|
|
334
|
-
profiler->active_profiles.erase(profile_id);
|
|
335
|
-
delete sentry_profile;
|
|
336
|
-
};
|
|
337
|
-
|
|
338
345
|
v8::CpuProfile *SentryProfile::Stop(Profiler *profiler) {
|
|
339
346
|
// Stop the CPU Profiler
|
|
340
347
|
v8::CpuProfile *profile = profiler->cpu_profiler->StopProfiling(
|
|
@@ -375,6 +382,21 @@ const std::vector<double> &SentryProfile::cpu_usage_values() const {
|
|
|
375
382
|
const uint16_t &SentryProfile::cpu_usage_write_index() const {
|
|
376
383
|
return cpu_write_index;
|
|
377
384
|
};
|
|
385
|
+
const uint64_t &SentryProfile::profile_start_timestamp() const {
|
|
386
|
+
return timestamp;
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
static void CleanupSentryProfile(Profiler *profiler,
|
|
390
|
+
SentryProfile *sentry_profile,
|
|
391
|
+
const std::string &profile_id) {
|
|
392
|
+
if (sentry_profile == nullptr) {
|
|
393
|
+
return;
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
sentry_profile->Stop(profiler);
|
|
397
|
+
profiler->active_profiles.erase(profile_id);
|
|
398
|
+
delete sentry_profile;
|
|
399
|
+
};
|
|
378
400
|
|
|
379
401
|
#ifdef _WIN32
|
|
380
402
|
static const char kPlatformSeparator = '\\';
|
|
@@ -523,8 +545,9 @@ CreateFrameNode(const napi_env &env, const v8::CpuProfileNode &node,
|
|
|
523
545
|
return js_node;
|
|
524
546
|
};
|
|
525
547
|
|
|
526
|
-
napi_value CreateSample(const napi_env &env, const
|
|
527
|
-
const int64_t
|
|
548
|
+
napi_value CreateSample(const napi_env &env, const enum ProfileFormat format,
|
|
549
|
+
const uint32_t stack_id, const int64_t sample_timestamp,
|
|
550
|
+
const double chunk_timestamp,
|
|
528
551
|
const uint32_t thread_id) {
|
|
529
552
|
napi_value js_node;
|
|
530
553
|
napi_create_object(env, &js_node);
|
|
@@ -538,11 +561,20 @@ napi_value CreateSample(const napi_env &env, const uint32_t stack_id,
|
|
|
538
561
|
NAPI_AUTO_LENGTH, &thread_id_prop);
|
|
539
562
|
napi_set_named_property(env, js_node, "thread_id", thread_id_prop);
|
|
540
563
|
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
564
|
+
switch (format) {
|
|
565
|
+
case ProfileFormat::kFormatThread: {
|
|
566
|
+
napi_value timestamp;
|
|
567
|
+
napi_create_int64(env, sample_timestamp, ×tamp);
|
|
568
|
+
napi_set_named_property(env, js_node, "elapsed_since_start_ns", timestamp);
|
|
569
|
+
} break;
|
|
570
|
+
case ProfileFormat::kFormatChunk: {
|
|
571
|
+
napi_value timestamp;
|
|
572
|
+
napi_create_double(env, chunk_timestamp, ×tamp);
|
|
573
|
+
napi_set_named_property(env, js_node, "timestamp", timestamp);
|
|
574
|
+
} break;
|
|
575
|
+
default:
|
|
576
|
+
break;
|
|
577
|
+
}
|
|
546
578
|
|
|
547
579
|
return js_node;
|
|
548
580
|
};
|
|
@@ -561,11 +593,13 @@ std::string hashCpuProfilerNodeByPath(const v8::CpuProfileNode *node,
|
|
|
561
593
|
}
|
|
562
594
|
|
|
563
595
|
static void GetSamples(const napi_env &env, const v8::CpuProfile *profile,
|
|
596
|
+
ProfileFormat format,
|
|
597
|
+
const uint64_t profile_start_timestamp_ms,
|
|
564
598
|
const uint32_t thread_id, napi_value &samples,
|
|
565
599
|
napi_value &stacks, napi_value &frames,
|
|
566
600
|
napi_value &resources) {
|
|
567
601
|
const int64_t profile_start_time_us = profile->GetStartTime();
|
|
568
|
-
const
|
|
602
|
+
const int64_t sampleCount = profile->GetSamplesCount();
|
|
569
603
|
|
|
570
604
|
uint32_t unique_stack_id = 0;
|
|
571
605
|
uint32_t unique_frame_id = 0;
|
|
@@ -585,7 +619,7 @@ static void GetSamples(const napi_env &env, const v8::CpuProfile *profile,
|
|
|
585
619
|
uint32_t stack_index = unique_stack_id;
|
|
586
620
|
|
|
587
621
|
const v8::CpuProfileNode *node = profile->GetSample(i);
|
|
588
|
-
const int64_t
|
|
622
|
+
const int64_t sample_timestamp_us = profile->GetSampleTimestamp(i);
|
|
589
623
|
|
|
590
624
|
// If a node was only on top of the stack once, then it will only ever
|
|
591
625
|
// be inserted once and there is no need for hashing.
|
|
@@ -604,8 +638,16 @@ static void GetSamples(const napi_env &env, const v8::CpuProfile *profile,
|
|
|
604
638
|
}
|
|
605
639
|
}
|
|
606
640
|
|
|
607
|
-
|
|
608
|
-
|
|
641
|
+
uint64_t sample_delta_us = sample_timestamp_us - profile_start_time_us;
|
|
642
|
+
uint64_t sample_timestamp_ns = sample_delta_us * 1e3;
|
|
643
|
+
uint64_t sample_offset_from_profile_start_ms =
|
|
644
|
+
(sample_timestamp_us - profile_start_time_us) * 1e-3;
|
|
645
|
+
double seconds_since_start =
|
|
646
|
+
profile_start_timestamp_ms + sample_offset_from_profile_start_ms;
|
|
647
|
+
|
|
648
|
+
napi_value sample = nullptr;
|
|
649
|
+
sample = CreateSample(env, format, stack_index, sample_timestamp_ns,
|
|
650
|
+
seconds_since_start, thread_id);
|
|
609
651
|
|
|
610
652
|
if (stack_index != unique_stack_id) {
|
|
611
653
|
napi_value index;
|
|
@@ -666,19 +708,19 @@ static void GetSamples(const napi_env &env, const v8::CpuProfile *profile,
|
|
|
666
708
|
}
|
|
667
709
|
}
|
|
668
710
|
|
|
669
|
-
static napi_value
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
if (size > values.size() || size >
|
|
711
|
+
static napi_value TranslateMeasurementsDouble(
|
|
712
|
+
const napi_env &env, const enum ProfileFormat format, const char *unit,
|
|
713
|
+
const uint64_t profile_start_timestamp_ms, const uint16_t size,
|
|
714
|
+
const std::vector<double> &values,
|
|
715
|
+
const std::vector<uint64_t> ×tamps_ns) {
|
|
716
|
+
if (size > values.size() || size > timestamps_ns.size()) {
|
|
675
717
|
napi_throw_range_error(env, "NAPI_ERROR",
|
|
676
718
|
"CPU measurement size is larger than the number of "
|
|
677
719
|
"values or timestamps");
|
|
678
720
|
return nullptr;
|
|
679
721
|
}
|
|
680
722
|
|
|
681
|
-
if (values.size() !=
|
|
723
|
+
if (values.size() != timestamps_ns.size()) {
|
|
682
724
|
napi_throw_range_error(env, "NAPI_ERROR",
|
|
683
725
|
"CPU measurement entries are corrupt, expected "
|
|
684
726
|
"values and timestamps to be of equal length");
|
|
@@ -708,11 +750,19 @@ TranslateMeasurementsDouble(const napi_env &env, const char *unit,
|
|
|
708
750
|
}
|
|
709
751
|
}
|
|
710
752
|
|
|
711
|
-
napi_value ts;
|
|
712
|
-
napi_create_int64(env, timestamps[i], &ts);
|
|
713
|
-
|
|
714
753
|
napi_set_named_property(env, entry, "value", value);
|
|
715
|
-
|
|
754
|
+
|
|
755
|
+
if (format == ProfileFormat::kFormatThread) {
|
|
756
|
+
napi_value ts;
|
|
757
|
+
napi_create_int64(env, timestamps_ns[i], &ts);
|
|
758
|
+
napi_set_named_property(env, entry, "elapsed_since_start_ns", ts);
|
|
759
|
+
} else if (format == ProfileFormat::kFormatChunk) {
|
|
760
|
+
napi_value ts;
|
|
761
|
+
napi_create_double(
|
|
762
|
+
env, profile_start_timestamp_ms + (timestamps_ns[i] * 1e-6), &ts);
|
|
763
|
+
napi_set_named_property(env, entry, "timestamp", ts);
|
|
764
|
+
}
|
|
765
|
+
|
|
716
766
|
napi_set_element(env, values_array, i, entry);
|
|
717
767
|
}
|
|
718
768
|
|
|
@@ -722,17 +772,19 @@ TranslateMeasurementsDouble(const napi_env &env, const char *unit,
|
|
|
722
772
|
}
|
|
723
773
|
|
|
724
774
|
static napi_value
|
|
725
|
-
TranslateMeasurements(const napi_env &env, const
|
|
775
|
+
TranslateMeasurements(const napi_env &env, const enum ProfileFormat format,
|
|
776
|
+
const char *unit,
|
|
777
|
+
const uint64_t profile_start_timestamp_ms,
|
|
726
778
|
const uint16_t size, const std::vector<uint64_t> &values,
|
|
727
|
-
const std::vector<uint64_t> &
|
|
728
|
-
if (size > values.size() || size >
|
|
779
|
+
const std::vector<uint64_t> ×tamps_ns) {
|
|
780
|
+
if (size > values.size() || size > timestamps_ns.size()) {
|
|
729
781
|
napi_throw_range_error(env, "NAPI_ERROR",
|
|
730
782
|
"Memory measurement size is larger than the number "
|
|
731
783
|
"of values or timestamps");
|
|
732
784
|
return nullptr;
|
|
733
785
|
}
|
|
734
786
|
|
|
735
|
-
if (values.size() !=
|
|
787
|
+
if (values.size() != timestamps_ns.size()) {
|
|
736
788
|
napi_throw_range_error(env, "NAPI_ERROR",
|
|
737
789
|
"Memory measurement entries are corrupt, expected "
|
|
738
790
|
"values and timestamps to be of equal length");
|
|
@@ -756,11 +808,22 @@ TranslateMeasurements(const napi_env &env, const char *unit,
|
|
|
756
808
|
napi_value value;
|
|
757
809
|
napi_create_int64(env, values[i], &value);
|
|
758
810
|
|
|
759
|
-
napi_value ts;
|
|
760
|
-
napi_create_int64(env, timestamps[i], &ts);
|
|
761
|
-
|
|
762
811
|
napi_set_named_property(env, entry, "value", value);
|
|
763
|
-
|
|
812
|
+
switch (format) {
|
|
813
|
+
case ProfileFormat::kFormatThread: {
|
|
814
|
+
napi_value ts;
|
|
815
|
+
napi_create_int64(env, timestamps_ns[i], &ts);
|
|
816
|
+
napi_set_named_property(env, entry, "elapsed_since_start_ns", ts);
|
|
817
|
+
} break;
|
|
818
|
+
case ProfileFormat::kFormatChunk: {
|
|
819
|
+
napi_value ts;
|
|
820
|
+
napi_create_double(
|
|
821
|
+
env, profile_start_timestamp_ms + (timestamps_ns[i] * 1e-6), &ts);
|
|
822
|
+
napi_set_named_property(env, entry, "timestamp", ts);
|
|
823
|
+
} break;
|
|
824
|
+
default:
|
|
825
|
+
break;
|
|
826
|
+
}
|
|
764
827
|
napi_set_element(env, values_array, i, entry);
|
|
765
828
|
}
|
|
766
829
|
|
|
@@ -771,6 +834,8 @@ TranslateMeasurements(const napi_env &env, const char *unit,
|
|
|
771
834
|
|
|
772
835
|
static napi_value TranslateProfile(const napi_env &env,
|
|
773
836
|
const v8::CpuProfile *profile,
|
|
837
|
+
const enum ProfileFormat format,
|
|
838
|
+
const uint64_t profile_start_timestamp_ms,
|
|
774
839
|
const uint32_t thread_id,
|
|
775
840
|
bool collect_resources) {
|
|
776
841
|
napi_value js_profile;
|
|
@@ -800,7 +865,8 @@ static napi_value TranslateProfile(const napi_env &env,
|
|
|
800
865
|
napi_set_named_property(env, js_profile, "profiler_logging_mode",
|
|
801
866
|
logging_mode);
|
|
802
867
|
|
|
803
|
-
GetSamples(env, profile,
|
|
868
|
+
GetSamples(env, profile, format, profile_start_timestamp_ms, thread_id,
|
|
869
|
+
samples, stacks, frames, resources);
|
|
804
870
|
|
|
805
871
|
if (collect_resources) {
|
|
806
872
|
napi_set_named_property(env, js_profile, "resources", resources);
|
|
@@ -887,14 +953,14 @@ static napi_value StartProfiling(napi_env env, napi_callback_info info) {
|
|
|
887
953
|
// StopProfiling(string title)
|
|
888
954
|
// https://v8docs.nodesource.com/node-18.2/d2/d34/classv8_1_1_cpu_profiler.html#a40ca4c8a8aa4c9233aa2a2706457cc80
|
|
889
955
|
static napi_value StopProfiling(napi_env env, napi_callback_info info) {
|
|
890
|
-
size_t argc =
|
|
891
|
-
napi_value argv[
|
|
956
|
+
size_t argc = 4;
|
|
957
|
+
napi_value argv[4];
|
|
892
958
|
|
|
893
959
|
assert(napi_get_cb_info(env, info, &argc, argv, NULL, NULL) == napi_ok);
|
|
894
960
|
|
|
895
|
-
if (argc <
|
|
961
|
+
if (argc < 3) {
|
|
896
962
|
napi_throw_error(env, "NAPI_ERROR",
|
|
897
|
-
"StopProfiling expects at least
|
|
963
|
+
"StopProfiling expects at least three arguments.");
|
|
898
964
|
|
|
899
965
|
napi_value napi_null;
|
|
900
966
|
assert(napi_get_null(env, &napi_null) == napi_ok);
|
|
@@ -916,14 +982,17 @@ static napi_value StopProfiling(napi_env env, napi_callback_info info) {
|
|
|
916
982
|
return napi_null;
|
|
917
983
|
}
|
|
918
984
|
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
assert(napi_typeof(env, argv[1], &callbacktype1) == napi_ok);
|
|
985
|
+
size_t len;
|
|
986
|
+
assert(napi_get_value_string_utf8(env, argv[0], NULL, 0, &len) == napi_ok);
|
|
922
987
|
|
|
923
|
-
|
|
988
|
+
char *title = (char *)malloc(len + 1);
|
|
989
|
+
assert(napi_get_value_string_utf8(env, argv[0], title, len + 1, &len) ==
|
|
990
|
+
napi_ok);
|
|
991
|
+
|
|
992
|
+
if (len < 1) {
|
|
924
993
|
napi_throw_error(
|
|
925
994
|
env, "NAPI_ERROR",
|
|
926
|
-
"StopProfiling expects a
|
|
995
|
+
"StopProfiling expects a non empty string as first argument.");
|
|
927
996
|
|
|
928
997
|
napi_value napi_null;
|
|
929
998
|
assert(napi_get_null(env, &napi_null) == napi_ok);
|
|
@@ -931,16 +1000,13 @@ static napi_value StopProfiling(napi_env env, napi_callback_info info) {
|
|
|
931
1000
|
return napi_null;
|
|
932
1001
|
}
|
|
933
1002
|
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
char *title = (char *)malloc(len + 1);
|
|
938
|
-
assert(napi_get_value_string_utf8(env, argv[0], title, len + 1, &len) ==
|
|
939
|
-
napi_ok);
|
|
1003
|
+
// Verify the second argument is a number
|
|
1004
|
+
napi_valuetype callbacktype1;
|
|
1005
|
+
assert(napi_typeof(env, argv[1], &callbacktype1) == napi_ok);
|
|
940
1006
|
|
|
941
|
-
if (
|
|
1007
|
+
if (callbacktype1 != napi_number) {
|
|
942
1008
|
napi_throw_error(env, "NAPI_ERROR",
|
|
943
|
-
"StopProfiling expects a
|
|
1009
|
+
"StopProfiling expects a format type as second argument.");
|
|
944
1010
|
|
|
945
1011
|
napi_value napi_null;
|
|
946
1012
|
assert(napi_get_null(env, &napi_null) == napi_ok);
|
|
@@ -948,9 +1014,27 @@ static napi_value StopProfiling(napi_env env, napi_callback_info info) {
|
|
|
948
1014
|
return napi_null;
|
|
949
1015
|
}
|
|
950
1016
|
|
|
1017
|
+
// Verify the second argument is a number
|
|
1018
|
+
napi_valuetype callbacktype2;
|
|
1019
|
+
assert(napi_typeof(env, argv[2], &callbacktype2) == napi_ok);
|
|
1020
|
+
|
|
1021
|
+
if (callbacktype2 != napi_number) {
|
|
1022
|
+
napi_throw_error(
|
|
1023
|
+
env, "NAPI_ERROR",
|
|
1024
|
+
"StopProfiling expects a thread_id integer as third argument.");
|
|
1025
|
+
|
|
1026
|
+
napi_value napi_null;
|
|
1027
|
+
assert(napi_get_null(env, &napi_null) == napi_ok);
|
|
1028
|
+
return napi_null;
|
|
1029
|
+
}
|
|
1030
|
+
|
|
1031
|
+
// Get the value of the second argument and convert it to uint8
|
|
1032
|
+
int32_t format;
|
|
1033
|
+
assert(napi_get_value_int32(env, argv[1], &format) == napi_ok);
|
|
1034
|
+
|
|
951
1035
|
// Get the value of the second argument and convert it to uint64
|
|
952
1036
|
int64_t thread_id;
|
|
953
|
-
assert(napi_get_value_int64(env, argv[
|
|
1037
|
+
assert(napi_get_value_int64(env, argv[2], &thread_id) == napi_ok);
|
|
954
1038
|
|
|
955
1039
|
// Get profiler from instance data
|
|
956
1040
|
Profiler *profiler;
|
|
@@ -962,7 +1046,6 @@ static napi_value StopProfiling(napi_env env, napi_callback_info info) {
|
|
|
962
1046
|
|
|
963
1047
|
napi_value napi_null;
|
|
964
1048
|
assert(napi_get_null(env, &napi_null) == napi_ok);
|
|
965
|
-
|
|
966
1049
|
return napi_null;
|
|
967
1050
|
}
|
|
968
1051
|
|
|
@@ -989,23 +1072,39 @@ static napi_value StopProfiling(napi_env env, napi_callback_info info) {
|
|
|
989
1072
|
};
|
|
990
1073
|
|
|
991
1074
|
napi_valuetype callbacktype3;
|
|
992
|
-
assert(napi_typeof(env, argv[
|
|
1075
|
+
assert(napi_typeof(env, argv[3], &callbacktype3) == napi_ok);
|
|
993
1076
|
|
|
994
1077
|
bool collect_resources;
|
|
995
|
-
napi_get_value_bool(env, argv[
|
|
1078
|
+
napi_get_value_bool(env, argv[3], &collect_resources);
|
|
1079
|
+
|
|
1080
|
+
const ProfileFormat format_type = static_cast<ProfileFormat>(format);
|
|
1081
|
+
|
|
1082
|
+
if (format_type != ProfileFormat::kFormatThread &&
|
|
1083
|
+
format_type != ProfileFormat::kFormatChunk) {
|
|
1084
|
+
napi_throw_error(
|
|
1085
|
+
env, "NAPI_ERROR",
|
|
1086
|
+
"StopProfiling expects a valid format type as second argument.");
|
|
1087
|
+
|
|
1088
|
+
napi_value napi_null;
|
|
1089
|
+
assert(napi_get_null(env, &napi_null) == napi_ok);
|
|
1090
|
+
return napi_null;
|
|
1091
|
+
}
|
|
996
1092
|
|
|
997
|
-
napi_value js_profile =
|
|
998
|
-
|
|
1093
|
+
napi_value js_profile = TranslateProfile(
|
|
1094
|
+
env, cpu_profile, format_type, profile->second->profile_start_timestamp(),
|
|
1095
|
+
thread_id, collect_resources);
|
|
999
1096
|
|
|
1000
1097
|
napi_value measurements;
|
|
1001
1098
|
napi_create_object(env, &measurements);
|
|
1002
1099
|
|
|
1003
1100
|
if (profile->second->heap_usage_write_index() > 0) {
|
|
1004
1101
|
static const char *memory_unit = "byte";
|
|
1005
|
-
napi_value heap_usage_measurements =
|
|
1006
|
-
env,
|
|
1007
|
-
|
|
1008
|
-
|
|
1102
|
+
napi_value heap_usage_measurements =
|
|
1103
|
+
TranslateMeasurements(env, format_type, memory_unit,
|
|
1104
|
+
profile->second->profile_start_timestamp(),
|
|
1105
|
+
profile->second->heap_usage_write_index(),
|
|
1106
|
+
profile->second->heap_usage_values(),
|
|
1107
|
+
profile->second->heap_usage_timestamps());
|
|
1009
1108
|
|
|
1010
1109
|
if (heap_usage_measurements != nullptr) {
|
|
1011
1110
|
napi_set_named_property(env, measurements, "memory_footprint",
|
|
@@ -1016,7 +1115,8 @@ static napi_value StopProfiling(napi_env env, napi_callback_info info) {
|
|
|
1016
1115
|
if (profile->second->cpu_usage_write_index() > 0) {
|
|
1017
1116
|
static const char *cpu_unit = "percent";
|
|
1018
1117
|
napi_value cpu_usage_measurements = TranslateMeasurementsDouble(
|
|
1019
|
-
env, cpu_unit, profile->second->
|
|
1118
|
+
env, format_type, cpu_unit, profile->second->profile_start_timestamp(),
|
|
1119
|
+
profile->second->cpu_usage_write_index(),
|
|
1020
1120
|
profile->second->cpu_usage_values(),
|
|
1021
1121
|
profile->second->cpu_usage_timestamps());
|
|
1022
1122
|
|
|
@@ -1049,6 +1149,7 @@ void FreeAddonData(napi_env env, void *data, void *hint) {
|
|
|
1049
1149
|
|
|
1050
1150
|
if (profiler->cpu_profiler != nullptr) {
|
|
1051
1151
|
profiler->cpu_profiler->Dispose();
|
|
1152
|
+
profiler->cpu_profiler = nullptr;
|
|
1052
1153
|
}
|
|
1053
1154
|
|
|
1054
1155
|
delete profiler;
|