@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.
- package/binding.gyp +130 -34
- package/bindings/binding.cc +13 -0
- package/bindings/code-event-record.cc +115 -0
- package/bindings/code-event-record.hh +67 -0
- package/bindings/code-map.cc +112 -0
- package/bindings/code-map.hh +47 -0
- package/bindings/cpu-time.cc +89 -0
- package/bindings/cpu-time.hh +35 -0
- package/bindings/location.cc +117 -0
- package/bindings/location.hh +43 -0
- package/bindings/per-isolate-data.cc +42 -0
- package/bindings/per-isolate-data.hh +26 -0
- package/bindings/profilers/cpu.cc +285 -0
- package/bindings/profilers/cpu.hh +78 -0
- package/bindings/profilers/heap.cc +112 -0
- package/bindings/profilers/heap.hh +40 -0
- package/bindings/profilers/wall.cc +306 -0
- package/bindings/profilers/wall.hh +28 -0
- package/bindings/sample.cc +160 -0
- package/bindings/sample.hh +48 -0
- package/bindings/test/binding.cc +59 -0
- package/bindings/test/code-event-record.test.cc +81 -0
- package/bindings/test/code-event-record.test.hh +5 -0
- package/bindings/test/code-map.test.cc +77 -0
- package/bindings/test/code-map.test.hh +5 -0
- package/bindings/test/cpu-time.test.cc +30 -0
- package/bindings/test/cpu-time.test.hh +5 -0
- package/bindings/test/location.test.cc +39 -0
- package/bindings/test/location.test.hh +5 -0
- package/bindings/test/profilers/cpu.test.cc +88 -0
- package/bindings/test/profilers/cpu.test.hh +5 -0
- package/bindings/test/sample.test.cc +128 -0
- package/bindings/test/sample.test.hh +5 -0
- package/bindings/test/tap.h +830 -0
- package/bindings/wrap.hh +20 -0
- package/out/src/cpu-profiler-bindings.d.ts +1 -0
- package/out/src/cpu-profiler-bindings.js +23 -0
- package/out/src/cpu-profiler-bindings.js.map +1 -0
- package/out/src/cpu-profiler.d.ts +19 -0
- package/out/src/cpu-profiler.js +94 -0
- package/out/src/cpu-profiler.js.map +1 -0
- package/out/src/index.d.ts +2 -0
- package/out/src/index.js +3 -1
- package/out/src/index.js.map +1 -1
- package/out/src/profile-encoder.js +3 -14
- package/out/src/profile-encoder.js.map +1 -1
- package/out/src/profile-serializer.d.ts +9 -1
- package/out/src/profile-serializer.js +73 -1
- package/out/src/profile-serializer.js.map +1 -1
- package/out/src/sourcemapper/sourcemapper.js +71 -88
- package/out/src/sourcemapper/sourcemapper.js.map +1 -1
- package/out/src/time-profiler.js +4 -15
- package/out/src/time-profiler.js.map +1 -1
- package/out/src/v8-types.d.ts +38 -0
- package/out/third_party/cloud-debug-nodejs/src/agent/io/scanner.js +6 -17
- package/out/third_party/cloud-debug-nodejs/src/agent/io/scanner.js.map +1 -1
- package/package-lock.json +5627 -0
- package/package.json +12 -14
- package/prebuilds/darwin-arm64/node-102.node +0 -0
- package/prebuilds/darwin-arm64/node-108.node +0 -0
- package/prebuilds/darwin-arm64/node-72.node +0 -0
- package/prebuilds/darwin-arm64/node-79.node +0 -0
- package/prebuilds/darwin-arm64/node-83.node +0 -0
- package/prebuilds/darwin-arm64/node-88.node +0 -0
- package/prebuilds/darwin-arm64/node-93.node +0 -0
- package/prebuilds/darwin-ia32/node-102.node +0 -0
- package/prebuilds/darwin-ia32/node-108.node +0 -0
- package/prebuilds/darwin-ia32/node-72.node +0 -0
- package/prebuilds/darwin-ia32/node-79.node +0 -0
- package/prebuilds/darwin-ia32/node-83.node +0 -0
- package/prebuilds/darwin-ia32/node-88.node +0 -0
- package/prebuilds/darwin-ia32/node-93.node +0 -0
- package/prebuilds/darwin-x64/node-102.node +0 -0
- package/prebuilds/darwin-x64/node-108.node +0 -0
- package/prebuilds/darwin-x64/node-72.node +0 -0
- package/prebuilds/darwin-x64/node-79.node +0 -0
- package/prebuilds/darwin-x64/node-83.node +0 -0
- package/prebuilds/darwin-x64/node-88.node +0 -0
- package/prebuilds/darwin-x64/node-93.node +0 -0
- package/prebuilds/linux-ia32/node-72.node +0 -0
- package/prebuilds/linux-ia32/node-79.node +0 -0
- package/prebuilds/linux-x64/node-102.node +0 -0
- package/prebuilds/linux-x64/node-108.node +0 -0
- package/prebuilds/linux-x64/node-72.node +0 -0
- package/prebuilds/linux-x64/node-79.node +0 -0
- package/prebuilds/linux-x64/node-83.node +0 -0
- package/prebuilds/linux-x64/node-88.node +0 -0
- package/prebuilds/linux-x64/node-93.node +0 -0
- package/prebuilds/win32-ia32/node-102.node +0 -0
- package/prebuilds/win32-ia32/node-72.node +0 -0
- package/prebuilds/win32-ia32/node-79.node +0 -0
- package/prebuilds/win32-ia32/node-83.node +0 -0
- package/prebuilds/win32-ia32/node-88.node +0 -0
- package/prebuilds/win32-ia32/node-93.node +0 -0
- package/prebuilds/win32-x64/node-102.node +0 -0
- package/prebuilds/win32-x64/node-108.node +0 -0
- package/prebuilds/win32-x64/node-72.node +0 -0
- package/prebuilds/win32-x64/node-79.node +0 -0
- package/prebuilds/win32-x64/node-83.node +0 -0
- package/prebuilds/win32-x64/node-88.node +0 -0
- package/prebuilds/win32-x64/node-93.node +0 -0
- package/scripts/require-package-json.js +11 -11
- package/scripts/should_rebuild.js +3 -3
- package/bindings/profiler.cc +0 -406
- package/scripts/preinstall.js +0 -36
package/binding.gyp
CHANGED
|
@@ -1,40 +1,136 @@
|
|
|
1
1
|
{
|
|
2
|
-
"
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
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
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
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
|