@datadog/pprof 0.4.0 → 0.5.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 (105) hide show
  1. package/binding.gyp +130 -34
  2. package/bindings/binding.cc +13 -0
  3. package/bindings/code-event-record.cc +115 -0
  4. package/bindings/code-event-record.hh +67 -0
  5. package/bindings/code-map.cc +112 -0
  6. package/bindings/code-map.hh +47 -0
  7. package/bindings/cpu-time.cc +89 -0
  8. package/bindings/cpu-time.hh +35 -0
  9. package/bindings/location.cc +117 -0
  10. package/bindings/location.hh +43 -0
  11. package/bindings/per-isolate-data.cc +42 -0
  12. package/bindings/per-isolate-data.hh +26 -0
  13. package/bindings/profilers/cpu.cc +285 -0
  14. package/bindings/profilers/cpu.hh +78 -0
  15. package/bindings/profilers/heap.cc +112 -0
  16. package/bindings/profilers/heap.hh +40 -0
  17. package/bindings/profilers/wall.cc +306 -0
  18. package/bindings/profilers/wall.hh +28 -0
  19. package/bindings/sample.cc +160 -0
  20. package/bindings/sample.hh +48 -0
  21. package/bindings/test/binding.cc +59 -0
  22. package/bindings/test/code-event-record.test.cc +81 -0
  23. package/bindings/test/code-event-record.test.hh +5 -0
  24. package/bindings/test/code-map.test.cc +77 -0
  25. package/bindings/test/code-map.test.hh +5 -0
  26. package/bindings/test/cpu-time.test.cc +30 -0
  27. package/bindings/test/cpu-time.test.hh +5 -0
  28. package/bindings/test/location.test.cc +39 -0
  29. package/bindings/test/location.test.hh +5 -0
  30. package/bindings/test/profilers/cpu.test.cc +88 -0
  31. package/bindings/test/profilers/cpu.test.hh +5 -0
  32. package/bindings/test/sample.test.cc +128 -0
  33. package/bindings/test/sample.test.hh +5 -0
  34. package/bindings/test/tap.h +830 -0
  35. package/bindings/wrap.hh +20 -0
  36. package/out/src/cpu-profiler-bindings.d.ts +1 -0
  37. package/out/src/cpu-profiler-bindings.js +23 -0
  38. package/out/src/cpu-profiler-bindings.js.map +1 -0
  39. package/out/src/cpu-profiler.d.ts +19 -0
  40. package/out/src/cpu-profiler.js +94 -0
  41. package/out/src/cpu-profiler.js.map +1 -0
  42. package/out/src/index.d.ts +2 -0
  43. package/out/src/index.js +3 -1
  44. package/out/src/index.js.map +1 -1
  45. package/out/src/profile-encoder.js +3 -14
  46. package/out/src/profile-encoder.js.map +1 -1
  47. package/out/src/profile-serializer.d.ts +9 -1
  48. package/out/src/profile-serializer.js +73 -1
  49. package/out/src/profile-serializer.js.map +1 -1
  50. package/out/src/sourcemapper/sourcemapper.js +71 -88
  51. package/out/src/sourcemapper/sourcemapper.js.map +1 -1
  52. package/out/src/time-profiler.js +4 -15
  53. package/out/src/time-profiler.js.map +1 -1
  54. package/out/src/v8-types.d.ts +38 -0
  55. package/out/third_party/cloud-debug-nodejs/src/agent/io/scanner.js +6 -17
  56. package/out/third_party/cloud-debug-nodejs/src/agent/io/scanner.js.map +1 -1
  57. package/package-lock.json +5627 -0
  58. package/package.json +12 -14
  59. package/prebuilds/darwin-arm64/node-102.node +0 -0
  60. package/prebuilds/darwin-arm64/node-108.node +0 -0
  61. package/prebuilds/darwin-arm64/node-72.node +0 -0
  62. package/prebuilds/darwin-arm64/node-79.node +0 -0
  63. package/prebuilds/darwin-arm64/node-83.node +0 -0
  64. package/prebuilds/darwin-arm64/node-88.node +0 -0
  65. package/prebuilds/darwin-arm64/node-93.node +0 -0
  66. package/prebuilds/darwin-ia32/node-102.node +0 -0
  67. package/prebuilds/darwin-ia32/node-108.node +0 -0
  68. package/prebuilds/darwin-ia32/node-72.node +0 -0
  69. package/prebuilds/darwin-ia32/node-79.node +0 -0
  70. package/prebuilds/darwin-ia32/node-83.node +0 -0
  71. package/prebuilds/darwin-ia32/node-88.node +0 -0
  72. package/prebuilds/darwin-ia32/node-93.node +0 -0
  73. package/prebuilds/darwin-x64/node-102.node +0 -0
  74. package/prebuilds/darwin-x64/node-108.node +0 -0
  75. package/prebuilds/darwin-x64/node-72.node +0 -0
  76. package/prebuilds/darwin-x64/node-79.node +0 -0
  77. package/prebuilds/darwin-x64/node-83.node +0 -0
  78. package/prebuilds/darwin-x64/node-88.node +0 -0
  79. package/prebuilds/darwin-x64/node-93.node +0 -0
  80. package/prebuilds/linux-ia32/node-72.node +0 -0
  81. package/prebuilds/linux-ia32/node-79.node +0 -0
  82. package/prebuilds/linux-x64/node-102.node +0 -0
  83. package/prebuilds/linux-x64/node-108.node +0 -0
  84. package/prebuilds/linux-x64/node-72.node +0 -0
  85. package/prebuilds/linux-x64/node-79.node +0 -0
  86. package/prebuilds/linux-x64/node-83.node +0 -0
  87. package/prebuilds/linux-x64/node-88.node +0 -0
  88. package/prebuilds/linux-x64/node-93.node +0 -0
  89. package/prebuilds/win32-ia32/node-102.node +0 -0
  90. package/prebuilds/win32-ia32/node-72.node +0 -0
  91. package/prebuilds/win32-ia32/node-79.node +0 -0
  92. package/prebuilds/win32-ia32/node-83.node +0 -0
  93. package/prebuilds/win32-ia32/node-88.node +0 -0
  94. package/prebuilds/win32-ia32/node-93.node +0 -0
  95. package/prebuilds/win32-x64/node-102.node +0 -0
  96. package/prebuilds/win32-x64/node-108.node +0 -0
  97. package/prebuilds/win32-x64/node-72.node +0 -0
  98. package/prebuilds/win32-x64/node-79.node +0 -0
  99. package/prebuilds/win32-x64/node-83.node +0 -0
  100. package/prebuilds/win32-x64/node-88.node +0 -0
  101. package/prebuilds/win32-x64/node-93.node +0 -0
  102. package/scripts/require-package-json.js +11 -11
  103. package/scripts/should_rebuild.js +3 -3
  104. package/bindings/profiler.cc +0 -406
  105. package/scripts/preinstall.js +0 -36
package/binding.gyp CHANGED
@@ -1,40 +1,136 @@
1
1
  {
2
- "targets": [
3
- {
4
- "target_name": "dd-pprof",
5
- "sources": [
6
- "bindings/profiler.cc",
7
- ],
8
- "include_dirs": ["<!(node -e \"require('nan')\")"],
9
- "xcode_settings": {
10
- "MACOSX_DEPLOYMENT_TARGET": "10.10",
11
- "OTHER_CFLAGS": [
12
- "-std=c++14",
13
- "-stdlib=libc++",
14
- "-Wall",
15
- "-Werror",
16
- "-Wno-deprecated-declarations",
17
- ]
2
+ "variables": {
3
+ "asan%": 0,
4
+ "lsan%": 0,
5
+ "ubsan%": 0,
6
+ },
7
+ "conditions": [
8
+ ["OS == 'mac'", {
9
+ "xcode_settings": {
10
+ "MACOSX_DEPLOYMENT_TARGET": "10.10",
11
+ 'CLANG_CXX_LIBRARY': 'libc++',
12
+ "OTHER_CFLAGS": [
13
+ "-std=c++14",
14
+ "-stdlib=libc++",
15
+ "-Wall",
16
+ "-Werror",
17
+ "-Wno-deprecated-declarations",
18
+ ]
19
+ },
20
+ }],
21
+ ["OS == 'linux'", {
22
+ "link_settings": {
23
+ "libraries": ["-lrt"]
18
24
  },
19
- "conditions": [
20
- ["OS == 'linux'", {
21
- "cflags": [
22
- "-std=c++11",
23
- "-Wall",
24
- "-Werror"
25
- ],
26
- "cflags_cc": [
27
- "-Wno-cast-function-type",
28
- # TODO: Remove when nan is updated to support v18 properly
29
- "-Wno-deprecated-declarations",
30
- ]
31
- }],
32
- ["OS == 'win'", {
33
- "cflags": [
34
- "/WX"
35
- ]
36
- }]
25
+ "cflags": [
26
+ "-std=c++14",
27
+ "-Wall",
28
+ "-Werror"
29
+ ],
30
+ "cflags_cc": [
31
+ "-Wno-cast-function-type",
32
+ # TODO: Remove when nan is updated to support v18 properly
33
+ "-Wno-deprecated-declarations",
34
+ ]
35
+ }],
36
+ ["OS == 'win'", {
37
+ "cflags": [
38
+ "/WX"
37
39
  ]
40
+ }],
41
+ # No macOS support for -fsanitize=leak
42
+ ["lsan == 'true' and OS != 'mac'", {
43
+ "cflags+": ["-fsanitize=leak"],
44
+ "ldflags": ["-fsanitize=leak"],
45
+ }],
46
+ ["asan == 'true' and OS != 'mac'", {
47
+ "cflags+": [
48
+ "-fno-omit-frame-pointer",
49
+ "-fsanitize=address",
50
+ "-fsanitize-address-use-after-scope",
51
+ ],
52
+ "cflags!": [ "-fomit-frame-pointer" ],
53
+ "ldflags": [ "-fsanitize=address" ],
54
+ }],
55
+ ["asan == 'true' and OS == 'mac'", {
56
+ "xcode_settings+": {
57
+ "OTHER_CFLAGS+": [
58
+ "-fno-omit-frame-pointer",
59
+ "-gline-tables-only",
60
+ "-fsanitize=address",
61
+ ],
62
+ "OTHER_CFLAGS!": [
63
+ "-fomit-frame-pointer",
64
+ ],
65
+ "OTHER_LDFLAGS": [
66
+ "-fsanitize=address",
67
+ ],
68
+ },
69
+ }],
70
+ # UBSAN
71
+ ["ubsan == 'true' and OS != 'mac'", {
72
+ "cflags+": [
73
+ "-fsanitize=undefined,alignment,bounds",
74
+ "-fno-sanitize-recover",
75
+ ],
76
+ "ldflags": [
77
+ "-fsanitize=undefined,alignment,bounds"
78
+ ],
79
+ }],
80
+ ["ubsan == 'true' and OS == 'mac'", {
81
+ "xcode_settings+": {
82
+ "OTHER_CFLAGS+": [
83
+ "-fsanitize=undefined,alignment,bounds",
84
+ "-fno-sanitize-recover",
85
+ ],
86
+ "OTHER_LDFLAGS": [
87
+ "-fsanitize=undefined,alignment,bounds"
88
+ ],
89
+ },
90
+ }],
91
+ ],
92
+ "targets": [
93
+ {
94
+ "target_name": "dd_pprof",
95
+ "sources": [
96
+ "bindings/profilers/cpu.cc",
97
+ "bindings/profilers/heap.cc",
98
+ "bindings/profilers/wall.cc",
99
+ "bindings/code-event-record.cc",
100
+ "bindings/code-map.cc",
101
+ "bindings/cpu-time.cc",
102
+ "bindings/location.cc",
103
+ "bindings/per-isolate-data.cc",
104
+ "bindings/sample.cc",
105
+ "bindings/binding.cc",
106
+ ],
107
+ "include_dirs": [
108
+ "<!(node -e \"require('nan')\")",
109
+ ],
110
+ },
111
+ {
112
+ "target_name": "test_dd_pprof",
113
+ "sources": [
114
+ "bindings/profilers/cpu.cc",
115
+ "bindings/profilers/heap.cc",
116
+ "bindings/profilers/wall.cc",
117
+ "bindings/code-event-record.cc",
118
+ "bindings/code-map.cc",
119
+ "bindings/cpu-time.cc",
120
+ "bindings/location.cc",
121
+ "bindings/per-isolate-data.cc",
122
+ "bindings/sample.cc",
123
+ "bindings/test/binding.cc",
124
+ "bindings/test/profilers/cpu.test.cc",
125
+ "bindings/test/code-event-record.test.cc",
126
+ "bindings/test/code-map.test.cc",
127
+ "bindings/test/cpu-time.test.cc",
128
+ "bindings/test/location.test.cc",
129
+ "bindings/test/sample.test.cc",
130
+ ],
131
+ "include_dirs": [
132
+ "<!(node -e \"require('nan')\")",
133
+ ],
38
134
  },
39
135
  ]
40
136
  }
@@ -0,0 +1,13 @@
1
+ #include "node.h"
2
+ #include "nan.h"
3
+ #include "v8.h"
4
+
5
+ #include "profilers/cpu.hh"
6
+ #include "profilers/heap.hh"
7
+ #include "profilers/wall.hh"
8
+
9
+ NODE_MODULE_INIT(/* exports, module, context */) {
10
+ dd::CpuProfiler::Init(exports);
11
+ dd::HeapProfiler::Init(exports);
12
+ dd::WallProfiler::Init(exports);
13
+ }
@@ -0,0 +1,115 @@
1
+ #include <node.h>
2
+
3
+ #include "code-event-record.hh"
4
+
5
+ namespace dd {
6
+
7
+ CodeEventRecord::CodeEventRecord(v8::Isolate *isolate,
8
+ uintptr_t address,
9
+ uintptr_t previousAddress,
10
+ size_t size,
11
+ int line,
12
+ int column,
13
+ std::string comment,
14
+ std::string functionName,
15
+ std::string scriptName)
16
+ : address(address),
17
+ previousAddress(previousAddress),
18
+ size(size),
19
+ line(line),
20
+ column(column),
21
+ comment(comment),
22
+ functionName(functionName),
23
+ scriptName(scriptName) {}
24
+
25
+ std::string safe_string(const char* maybe_string) {
26
+ return maybe_string == nullptr ? "" : maybe_string;
27
+ }
28
+
29
+ std::string safe_string(v8::Isolate* isolate, v8::Local<v8::String> maybe_string) {
30
+ auto len = maybe_string->Utf8Length(isolate);
31
+ std::string buffer(len + 1, 0);
32
+ maybe_string->WriteUtf8(isolate, &buffer[0], len + 1);
33
+ return std::string(buffer.c_str());
34
+ }
35
+
36
+ CodeEventRecord::CodeEventRecord(v8::Isolate* isolate, v8::CodeEvent* code_event)
37
+ : CodeEventRecord(
38
+ isolate,
39
+ code_event->GetCodeStartAddress(),
40
+ // CodeEvent::GetPreviousCodeStartAddress didn't exist until Node.js 13.
41
+ #if NODE_MODULE_VERSION > 79
42
+ code_event->GetPreviousCodeStartAddress(),
43
+ #else
44
+ 0,
45
+ #endif
46
+ code_event->GetCodeSize(),
47
+ code_event->GetScriptLine(),
48
+ code_event->GetScriptColumn(),
49
+ safe_string(code_event->GetComment()),
50
+ safe_string(isolate, code_event->GetFunctionName()),
51
+ safe_string(isolate, code_event->GetScriptName())
52
+ ) {}
53
+
54
+ void CodeEventRecord::SetScriptId(int _scriptId) {
55
+ scriptId = _scriptId;
56
+ }
57
+
58
+ v8::Local<v8::Integer> CodeEventRecord::GetScriptId(v8::Isolate* isolate) {
59
+ return v8::Integer::New(isolate, scriptId);
60
+ }
61
+
62
+ v8::Local<v8::Integer> CodeEventRecord::GetAddress(v8::Isolate* isolate) {
63
+ return v8::Integer::NewFromUnsigned(isolate, address);
64
+ }
65
+
66
+ v8::Local<v8::Integer> CodeEventRecord::GetPreviousAddress(v8::Isolate* isolate) {
67
+ return v8::Integer::NewFromUnsigned(isolate, previousAddress);
68
+ }
69
+
70
+ v8::Local<v8::Integer> CodeEventRecord::GetSize(v8::Isolate* isolate) {
71
+ return v8::Integer::NewFromUnsigned(isolate, size);
72
+ }
73
+
74
+ v8::Local<v8::Value> CodeEventRecord::GetFunctionName(v8::Isolate* isolate) {
75
+ if (functionName.empty()) {
76
+ return v8::Undefined(isolate);
77
+ }
78
+ return Nan::New(functionName).ToLocalChecked();
79
+ }
80
+
81
+ v8::Local<v8::Value> CodeEventRecord::GetScriptName(v8::Isolate* isolate) {
82
+ if (scriptName.empty()) {
83
+ return v8::Undefined(isolate);
84
+ }
85
+ return Nan::New(scriptName).ToLocalChecked();
86
+ }
87
+
88
+ v8::Local<v8::Integer> CodeEventRecord::GetLine(v8::Isolate* isolate) {
89
+ return v8::Integer::New(isolate, line);
90
+ }
91
+
92
+ v8::Local<v8::Integer> CodeEventRecord::GetColumn(v8::Isolate* isolate) {
93
+ return v8::Integer::New(isolate, column);
94
+ }
95
+
96
+ v8::Local<v8::Value> CodeEventRecord::GetComment(v8::Isolate* isolate) {
97
+ if (comment.empty()) {
98
+ return v8::Undefined(isolate);
99
+ }
100
+ return Nan::New(comment).ToLocalChecked();
101
+ }
102
+
103
+ bool CodeEventRecord::Equal(const CodeEventRecord* rhs) const {
104
+ return scriptId == rhs->scriptId &&
105
+ address == rhs->address &&
106
+ previousAddress == rhs->previousAddress &&
107
+ size == rhs->size &&
108
+ line == rhs->line &&
109
+ column == rhs->column &&
110
+ comment == rhs->comment &&
111
+ functionName == rhs->functionName &&
112
+ scriptName == rhs->scriptName;
113
+ }
114
+
115
+ }; // namespace dd
@@ -0,0 +1,67 @@
1
+ #pragma once
2
+
3
+ #include <string>
4
+ #include <map>
5
+
6
+ #include <nan.h>
7
+ #include <node_object_wrap.h> // cppcheck-suppress missingIncludeSystem
8
+ #include <v8-profiler.h>
9
+ #include <v8.h>
10
+
11
+ namespace dd {
12
+
13
+ class CodeMap;
14
+
15
+ class CodeEventRecord : public Nan::ObjectWrap {
16
+ private:
17
+ int scriptId = 0;
18
+ uintptr_t address;
19
+ uintptr_t previousAddress;
20
+ size_t size;
21
+ int line;
22
+ int column;
23
+ std::string comment;
24
+ std::string functionName;
25
+ std::string scriptName;
26
+
27
+ public:
28
+ explicit CodeEventRecord(v8::Isolate* isolate,
29
+ uintptr_t address,
30
+ uintptr_t previousAddress,
31
+ size_t size,
32
+ int line,
33
+ int column,
34
+ std::string comment,
35
+ v8::Local<v8::String> functionName,
36
+ v8::Local<v8::String> scriptName);
37
+
38
+ explicit CodeEventRecord(v8::Isolate* isolate,
39
+ uintptr_t address,
40
+ uintptr_t previousAddress = 0,
41
+ size_t size = 0,
42
+ int line = 0,
43
+ int column = 0,
44
+ std::string comment = "",
45
+ std::string functionName = "",
46
+ std::string scriptName = "");
47
+
48
+ explicit CodeEventRecord(v8::Isolate* isolate, v8::CodeEvent* code_event);
49
+
50
+ void SetScriptId(int _id);
51
+
52
+ v8::Local<v8::Integer> GetScriptId(v8::Isolate *isolate);
53
+ v8::Local<v8::Integer> GetAddress(v8::Isolate* isolate);
54
+ v8::Local<v8::Integer> GetPreviousAddress(v8::Isolate* isolate);
55
+ v8::Local<v8::Integer> GetSize(v8::Isolate* isolate);
56
+ v8::Local<v8::Integer> GetLine(v8::Isolate* isolate);
57
+ v8::Local<v8::Integer> GetColumn(v8::Isolate* isolate);
58
+ v8::Local<v8::Value> GetFunctionName(v8::Isolate* isolate);
59
+ v8::Local<v8::Value> GetScriptName(v8::Isolate* isolate);
60
+ v8::Local<v8::Value> GetComment(v8::Isolate* isolate);
61
+
62
+ bool Equal(const CodeEventRecord *rhs) const;
63
+
64
+ friend class CodeMap;
65
+ };
66
+
67
+ }; // namespace dd
@@ -0,0 +1,112 @@
1
+ #include <unordered_map>
2
+
3
+ #include <node.h>
4
+
5
+ #include "profilers/cpu.hh"
6
+ #include "code-map.hh"
7
+
8
+ namespace dd {
9
+
10
+ static std::unordered_map<v8::Isolate*, std::shared_ptr<CodeMap>> code_maps_;
11
+
12
+ CodeMap::CodeMap(v8::Isolate* isolate, CodeEntries entries)
13
+ : CodeEventHandler(isolate),
14
+ code_entries_(entries),
15
+ isolate_(isolate) {}
16
+
17
+ CodeMap::~CodeMap() {
18
+ Disable();
19
+ }
20
+
21
+ std::shared_ptr<CodeMap> CodeMap::For(v8::Isolate* isolate) {
22
+ auto maybe = code_maps_.find(isolate);
23
+ if (maybe != code_maps_.end()) {
24
+ return maybe->second;
25
+ }
26
+
27
+ code_maps_[isolate] = std::make_shared<CodeMap>(isolate);
28
+ return code_maps_[isolate];
29
+ }
30
+
31
+ CodeEntries CodeMap::Entries() {
32
+ return code_entries_;
33
+ }
34
+
35
+ void CodeMap::Enable() {
36
+ if (++refs == 1) {
37
+ CodeEventHandler::Enable();
38
+ isolate_->SetJitCodeEventHandler(v8::kJitCodeEventDefault,
39
+ StaticHandleJitEvent);
40
+ }
41
+ }
42
+
43
+ void CodeMap::Disable() {
44
+ if (--refs == 0) {
45
+ CodeEventHandler::Disable();
46
+ isolate_->SetJitCodeEventHandler(v8::kJitCodeEventDefault, nullptr);
47
+ code_entries_.clear();
48
+ }
49
+ }
50
+
51
+ // TODO: unsure of ordering but might need bi-directional merging for script id
52
+ void CodeMap::HandleJitEvent(const v8::JitCodeEvent* event) {
53
+ if (event->type == v8::JitCodeEvent::CODE_REMOVED) {
54
+ Remove(reinterpret_cast<uintptr_t>(event->code_start));
55
+ return;
56
+ }
57
+
58
+ CodeEntries::iterator it = code_entries_.find(
59
+ reinterpret_cast<uintptr_t>(event->code_start));
60
+
61
+ if (it != code_entries_.end() && !event->script.IsEmpty()) {
62
+ it->second->SetScriptId(event->script->GetId());
63
+ }
64
+ }
65
+
66
+ void CodeMap::StaticHandleJitEvent(const v8::JitCodeEvent* event) {
67
+ auto code_map = CodeMap::For(event->isolate);
68
+ code_map->HandleJitEvent(event);
69
+ }
70
+
71
+ // TODO: Figure out if additional checks are needed to cleanup expired regions.
72
+ // If size of previous is greater than offset of new position, the old record
73
+ // must be invalid, clean it up.
74
+ void CodeMap::Handle(v8::CodeEvent* code_event) {
75
+ #if NODE_MODULE_VERSION > 79
76
+ if (code_event->GetCodeType() == v8::CodeEventType::kRelocationType) {
77
+ CodeEntries::iterator it = code_entries_.find(
78
+ code_event->GetPreviousCodeStartAddress());
79
+ if (it != code_entries_.end()) {
80
+ code_entries_.erase(it);
81
+ }
82
+ }
83
+ #endif
84
+
85
+ Add(code_event->GetCodeStartAddress(),
86
+ std::make_shared<CodeEventRecord>(isolate_, code_event));
87
+ }
88
+
89
+ void CodeMap::Add(uintptr_t address, std::shared_ptr<CodeEventRecord> record) {
90
+ code_entries_.insert(std::make_pair(address, std::move(record)));
91
+ }
92
+
93
+ void CodeMap::Remove(uintptr_t address) {
94
+ code_entries_.erase(address);
95
+ }
96
+
97
+ void CodeMap::Clear() {
98
+ code_entries_.clear();
99
+ }
100
+
101
+ std::shared_ptr<CodeEventRecord> CodeMap::Lookup(uintptr_t address) {
102
+ CodeEntries::iterator it = code_entries_.upper_bound(address);
103
+ if (it == code_entries_.begin()) return nullptr;
104
+ --it;
105
+ uintptr_t start_address = it->first;
106
+ std::shared_ptr<CodeEventRecord> entry = it->second;
107
+ uintptr_t code_end = start_address + entry->size;
108
+ if (address >= code_end) return nullptr;
109
+ return entry;
110
+ }
111
+
112
+ }; // namespace dd
@@ -0,0 +1,47 @@
1
+ #pragma once
2
+
3
+ #include <string>
4
+ #include <map>
5
+
6
+ #include <node_object_wrap.h> // cppcheck-suppress missingIncludeSystem
7
+ #if NODE_MODULE_VERSION >= 102
8
+ #include <v8-callbacks.h>
9
+ #endif
10
+ #include <v8-profiler.h>
11
+ #include <v8.h>
12
+
13
+ #include "code-event-record.hh"
14
+
15
+ namespace dd {
16
+
17
+ using CodeEntries = std::map<uintptr_t, std::shared_ptr<CodeEventRecord>>;
18
+
19
+ class CodeMap : public v8::CodeEventHandler {
20
+ private:
21
+ CodeEntries code_entries_;
22
+ v8::Isolate* isolate_;
23
+ int refs = 0;
24
+
25
+ void HandleJitEvent(const v8::JitCodeEvent* event);
26
+ static void StaticHandleJitEvent(const v8::JitCodeEvent* event);
27
+
28
+ public:
29
+ explicit CodeMap(v8::Isolate* isolate, CodeEntries entries = {});
30
+ ~CodeMap();
31
+
32
+ static std::shared_ptr<CodeMap> For(v8::Isolate* isolate);
33
+
34
+ CodeEntries Entries();
35
+
36
+ void Enable();
37
+ void Disable();
38
+
39
+ void Add(uintptr_t address, std::shared_ptr<CodeEventRecord> record);
40
+ void Remove(uintptr_t address);
41
+ void Clear();
42
+
43
+ void Handle(v8::CodeEvent* code_event) override;
44
+ std::shared_ptr<CodeEventRecord> Lookup(uintptr_t address);
45
+ };
46
+
47
+ }; // namespace dd
@@ -0,0 +1,89 @@
1
+ #include "cpu-time.hh"
2
+
3
+ #ifdef __linux__
4
+ #include <errno.h>
5
+ #include <pthread.h>
6
+ #include <string.h>
7
+ #elif __APPLE__
8
+ #define _DARWIN_C_SOURCE
9
+ #include <mach/mach_error.h>
10
+ #include <mach/mach_init.h>
11
+ #include <mach/thread_act.h>
12
+ #elif _WIN32
13
+ #include <Windows.h>
14
+ #endif
15
+
16
+ namespace dd {
17
+
18
+ CpuTime::CpuTime(struct timespec time) : last_(time) {
19
+ #ifdef __linux__
20
+ pthread_getcpuclockid(pthread_self(), &clockid);
21
+ #elif __APPLE__
22
+ thread_ = mach_thread_self();
23
+ #elif _WIN32
24
+ thread_ = GetCurrentThread();
25
+ #endif
26
+ }
27
+
28
+ CpuTime::CpuTime()
29
+ : CpuTime(Now()) {}
30
+
31
+ int64_t CpuTime::Diff(struct timespec now) {
32
+ int64_t current = now.tv_sec * INT64_C(1000000000) + now.tv_nsec;
33
+ int64_t prev = last_.tv_sec * INT64_C(1000000000) + last_.tv_nsec;
34
+ int64_t cpu_time = current - prev;
35
+
36
+ last_ = now;
37
+
38
+ return cpu_time;
39
+ }
40
+
41
+ int64_t CpuTime::Diff() {
42
+ return Diff(Now());
43
+ }
44
+
45
+ struct timespec CpuTime::Now() {
46
+ struct timespec cpu_time = {0, 0};
47
+
48
+ #ifdef __linux__
49
+ if (clock_gettime(clockid, &cpu_time)) {
50
+ return (struct timespec){0, 0};
51
+ }
52
+ #elif __APPLE__
53
+ mach_msg_type_number_t count = THREAD_BASIC_INFO_COUNT;
54
+ thread_basic_info_data_t info;
55
+ kern_return_t kr =
56
+ thread_info(thread_, THREAD_BASIC_INFO, (thread_info_t)&info, &count);
57
+
58
+ if (kr != KERN_SUCCESS) {
59
+ return cpu_time;
60
+ }
61
+
62
+ cpu_time = {
63
+ // tv_sec
64
+ info.user_time.seconds + info.system_time.seconds,
65
+ // tv_nsec
66
+ (info.user_time.microseconds + info.system_time.microseconds) * 1000,
67
+ };
68
+ #elif _WIN32
69
+ FILETIME a, b, c, d;
70
+ if (!GetThreadTimes(thread_, &a, &b, &c, &d)) {
71
+ return cpu_time;
72
+ }
73
+
74
+ // Convert 100-ns interval to nanooseconds
75
+ uint64_t us = (((uint64_t)d.dwHighDateTime << 32) |
76
+ (uint64_t)d.dwLowDateTime) * 100;
77
+
78
+ cpu_time = {
79
+ // tv_sec
80
+ (time_t)(us / 1000000000),
81
+ // tv_nsec
82
+ (long)(us % 1000000000),
83
+ };
84
+ #endif
85
+
86
+ return cpu_time;
87
+ }
88
+
89
+ }
@@ -0,0 +1,35 @@
1
+ #pragma once
2
+
3
+ #include <stdint.h>
4
+ #include <time.h>
5
+
6
+ #ifdef __linux__
7
+ #include <pthread.h>
8
+ #elif __APPLE__
9
+ #include <mach/mach.h>
10
+ #elif _WIN32
11
+ #include <Windows.h>
12
+ #endif
13
+
14
+ namespace dd {
15
+
16
+ class CpuTime {
17
+ private:
18
+ struct timespec last_;
19
+ #ifdef __linux__
20
+ clockid_t clockid;
21
+ #elif __APPLE__
22
+ mach_port_t thread_;
23
+ #elif _WIN32
24
+ HANDLE thread_;
25
+ #endif
26
+
27
+ public:
28
+ CpuTime(struct timespec time);
29
+ CpuTime();
30
+ int64_t Diff(struct timespec time);
31
+ int64_t Diff();
32
+ struct timespec Now();
33
+ };
34
+
35
+ } // namespace dd