@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.
Files changed (81) hide show
  1. package/bindings/cpu_profiler.cc +174 -73
  2. package/lib/cjs/index.js +479 -154
  3. package/lib/cjs/index.js.map +1 -1
  4. package/lib/esm/index.js +478 -154
  5. package/lib/esm/index.js.map +1 -1
  6. package/lib/sentry_cpu_profiler-darwin-arm64-108.node +0 -0
  7. package/lib/sentry_cpu_profiler-darwin-arm64-115.node +0 -0
  8. package/lib/sentry_cpu_profiler-darwin-arm64-127.node +0 -0
  9. package/lib/sentry_cpu_profiler-darwin-arm64-93.node +0 -0
  10. package/lib/sentry_cpu_profiler-darwin-x64-108.node +0 -0
  11. package/lib/sentry_cpu_profiler-darwin-x64-115.node +0 -0
  12. package/lib/sentry_cpu_profiler-darwin-x64-127.node +0 -0
  13. package/lib/sentry_cpu_profiler-darwin-x64-93.node +0 -0
  14. package/lib/sentry_cpu_profiler-linux-arm64-glibc-108.node +0 -0
  15. package/lib/sentry_cpu_profiler-linux-arm64-glibc-115.node +0 -0
  16. package/lib/sentry_cpu_profiler-linux-arm64-glibc-127.node +0 -0
  17. package/lib/sentry_cpu_profiler-linux-arm64-glibc-93.node +0 -0
  18. package/lib/sentry_cpu_profiler-linux-arm64-musl-108.node +0 -0
  19. package/lib/sentry_cpu_profiler-linux-arm64-musl-115.node +0 -0
  20. package/lib/sentry_cpu_profiler-linux-arm64-musl-127.node +0 -0
  21. package/lib/sentry_cpu_profiler-linux-arm64-musl-93.node +0 -0
  22. package/lib/sentry_cpu_profiler-linux-x64-glibc-108.node +0 -0
  23. package/lib/sentry_cpu_profiler-linux-x64-glibc-115.node +0 -0
  24. package/lib/sentry_cpu_profiler-linux-x64-glibc-127.node +0 -0
  25. package/lib/sentry_cpu_profiler-linux-x64-glibc-93.node +0 -0
  26. package/lib/sentry_cpu_profiler-linux-x64-musl-108.node +0 -0
  27. package/lib/sentry_cpu_profiler-linux-x64-musl-115.node +0 -0
  28. package/lib/sentry_cpu_profiler-linux-x64-musl-127.node +0 -0
  29. package/lib/sentry_cpu_profiler-linux-x64-musl-93.node +0 -0
  30. package/lib/sentry_cpu_profiler-win32-x64-108.node +0 -0
  31. package/lib/sentry_cpu_profiler-win32-x64-115.node +0 -0
  32. package/lib/sentry_cpu_profiler-win32-x64-127.node +0 -0
  33. package/lib/sentry_cpu_profiler-win32-x64-93.node +0 -0
  34. package/lib/types/profiling-node/src/cpu_profiler.d.ts +16 -0
  35. package/lib/types/profiling-node/src/cpu_profiler.d.ts.map +1 -0
  36. package/lib/types/profiling-node/src/debug-build.d.ts.map +1 -0
  37. package/lib/types/profiling-node/src/index.d.ts.map +1 -0
  38. package/lib/types/profiling-node/src/integration.d.ts +57 -0
  39. package/lib/types/profiling-node/src/integration.d.ts.map +1 -0
  40. package/lib/types/profiling-node/src/nodeVersion.d.ts.map +1 -0
  41. package/lib/types/{spanProfileUtils.d.ts → profiling-node/src/spanProfileUtils.d.ts} +2 -2
  42. package/lib/types/profiling-node/src/spanProfileUtils.d.ts.map +1 -0
  43. package/lib/types/profiling-node/src/types.d.ts +60 -0
  44. package/lib/types/profiling-node/src/types.d.ts.map +1 -0
  45. package/lib/types/{utils.d.ts → profiling-node/src/utils.d.ts} +30 -4
  46. package/lib/types/profiling-node/src/utils.d.ts.map +1 -0
  47. package/lib/types/types/src/debugMeta.d.ts +28 -0
  48. package/lib/types/types/src/debugMeta.d.ts.map +1 -0
  49. package/lib/types/types/src/measurement.d.ts +24 -0
  50. package/lib/types/types/src/measurement.d.ts.map +1 -0
  51. package/lib/types/types/src/profiling.d.ts +126 -0
  52. package/lib/types/types/src/profiling.d.ts.map +1 -0
  53. package/lib/types-ts3.8/profiling-node/src/cpu_profiler.d.ts +16 -0
  54. package/lib/types-ts3.8/profiling-node/src/integration.d.ts +57 -0
  55. package/lib/types-ts3.8/{spanProfileUtils.d.ts → profiling-node/src/spanProfileUtils.d.ts} +2 -2
  56. package/lib/types-ts3.8/profiling-node/src/types.d.ts +60 -0
  57. package/lib/types-ts3.8/{utils.d.ts → profiling-node/src/utils.d.ts} +30 -4
  58. package/lib/types-ts3.8/types/src/debugMeta.d.ts +28 -0
  59. package/lib/types-ts3.8/types/src/measurement.d.ts +24 -0
  60. package/lib/types-ts3.8/types/src/profiling.d.ts +126 -0
  61. package/package.json +5 -5
  62. package/lib/types/cpu_profiler.d.ts +0 -10
  63. package/lib/types/cpu_profiler.d.ts.map +0 -1
  64. package/lib/types/debug-build.d.ts.map +0 -1
  65. package/lib/types/index.d.ts.map +0 -1
  66. package/lib/types/integration.d.ts +0 -14
  67. package/lib/types/integration.d.ts.map +0 -1
  68. package/lib/types/nodeVersion.d.ts.map +0 -1
  69. package/lib/types/spanProfileUtils.d.ts.map +0 -1
  70. package/lib/types/types.d.ts +0 -100
  71. package/lib/types/types.d.ts.map +0 -1
  72. package/lib/types/utils.d.ts.map +0 -1
  73. package/lib/types-ts3.8/cpu_profiler.d.ts +0 -10
  74. package/lib/types-ts3.8/integration.d.ts +0 -14
  75. package/lib/types-ts3.8/types.d.ts +0 -100
  76. /package/lib/types/{debug-build.d.ts → profiling-node/src/debug-build.d.ts} +0 -0
  77. /package/lib/types/{index.d.ts → profiling-node/src/index.d.ts} +0 -0
  78. /package/lib/types/{nodeVersion.d.ts → profiling-node/src/nodeVersion.d.ts} +0 -0
  79. /package/lib/types-ts3.8/{debug-build.d.ts → profiling-node/src/debug-build.d.ts} +0 -0
  80. /package/lib/types-ts3.8/{index.d.ts → profiling-node/src/index.d.ts} +0 -0
  81. /package/lib/types-ts3.8/{nodeVersion.d.ts → profiling-node/src/nodeVersion.d.ts} +0 -0
@@ -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.data = this;
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 uint32_t stack_id,
527
- const int64_t sample_timestamp_us,
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
- napi_value elapsed_since_start_ns_prop;
542
- napi_create_int64(env, sample_timestamp_us * 1000,
543
- &elapsed_since_start_ns_prop);
544
- napi_set_named_property(env, js_node, "elapsed_since_start_ns",
545
- elapsed_since_start_ns_prop);
564
+ switch (format) {
565
+ case ProfileFormat::kFormatThread: {
566
+ napi_value timestamp;
567
+ napi_create_int64(env, sample_timestamp, &timestamp);
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, &timestamp);
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 int sampleCount = profile->GetSamplesCount();
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 sample_timestamp = profile->GetSampleTimestamp(i);
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
- napi_value sample = CreateSample(
608
- env, stack_index, sample_timestamp - profile_start_time_us, thread_id);
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
- TranslateMeasurementsDouble(const napi_env &env, const char *unit,
671
- const uint16_t size,
672
- const std::vector<double> &values,
673
- const std::vector<uint64_t> &timestamps) {
674
- if (size > values.size() || size > timestamps.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> &timestamps_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() != timestamps.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
- napi_set_named_property(env, entry, "elapsed_since_start_ns", ts);
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 char *unit,
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> &timestamps) {
728
- if (size > values.size() || size > timestamps.size()) {
779
+ const std::vector<uint64_t> &timestamps_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() != timestamps.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
- napi_set_named_property(env, entry, "elapsed_since_start_ns", ts);
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, thread_id, samples, stacks, frames, resources);
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 = 3;
891
- napi_value argv[3];
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 < 2) {
961
+ if (argc < 3) {
896
962
  napi_throw_error(env, "NAPI_ERROR",
897
- "StopProfiling expects at least two arguments.");
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
- // Verify the second argument is a number
920
- napi_valuetype callbacktype1;
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
- if (callbacktype1 != napi_number) {
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 thread_id integer as second argument.");
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
- size_t len;
935
- assert(napi_get_value_string_utf8(env, argv[0], NULL, 0, &len) == napi_ok);
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 (len < 1) {
1007
+ if (callbacktype1 != napi_number) {
942
1008
  napi_throw_error(env, "NAPI_ERROR",
943
- "StopProfiling expects a string as first argument.");
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[1], &thread_id) == napi_ok);
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[2], &callbacktype3) == napi_ok);
1075
+ assert(napi_typeof(env, argv[3], &callbacktype3) == napi_ok);
993
1076
 
994
1077
  bool collect_resources;
995
- napi_get_value_bool(env, argv[2], &collect_resources);
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
- TranslateProfile(env, cpu_profile, thread_id, collect_resources);
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 = TranslateMeasurements(
1006
- env, memory_unit, profile->second->heap_usage_write_index(),
1007
- profile->second->heap_usage_values(),
1008
- profile->second->heap_usage_timestamps());
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->cpu_usage_write_index(),
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;