Skip to content

Commit 853753b

Browse files
committed
add manual profiling, prebuild all addons
1 parent 3cef3cd commit 853753b

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+694
-80
lines changed

.gitignore

-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
._
33
._.*
44
build
5-
prebuilt
65
node_modules
76
npm-debug.log
87
package-lock.json

README.md

+42-5
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ Learn more on the [features](https://stackimpact.com/features/) page (with scree
2121

2222
#### How it works
2323

24-
The StackImpact profiler agent is imported into a program and used as a normal package. When the program runs, various sampling profilers are started and stopped automatically by the agent and/or programmatically using the agent methods. The agent periodically reports recorded profiles and metrics to the StackImpact Dashboard. If an application has multiple processes, also referred to as workers, instances or nodes, only one or two processes will have active agents at any point of time.
24+
The StackImpact profiler agent is imported into a program and used as a normal package. When the program runs, various sampling profilers are started and stopped automatically by the agent and/or programmatically using the agent methods. The agent periodically reports recorded profiles and metrics to the StackImpact Dashboard. If an application has multiple processes, also referred to as workers, instances or nodes, only one or two processes will have active agents at any point of time. The agent can also operate in manual mode, which should be used in development only.
2525

2626

2727
#### Documentation
@@ -34,7 +34,7 @@ See full [documentation](https://stackimpact.com/docs/) for reference.
3434

3535
* Linux, OS X or Windows. Node.js v4.0.0 or higher.
3636
* CPU profiler is disabled by default for Node.js v7.0.0 to v8.9.3 due to memory leak in underlying V8's CPU profiler. To enable, add `cpuProfilerDisabled: false` to startup options.
37-
* Allocation profiler supports Node.js v6.0.0 and higher. The allocation profiler is disabled by default, since V8's heap sampling is still experimental and is seen to result in segmentation faults. To enable, add `allocationProfilerDisabled: false` to startup options.
37+
* Allocation profiler supports Node.js v6.0.0 and higher, but is disabled by default for Node.js v6.0.0 to v8.5.0 due to segfaults. To enable, add `allocationProfilerDisabled: false` to startup options.
3838
* Async profiler supports Node.js v8.1.0 and higher.
3939

4040

@@ -79,18 +79,18 @@ All initialization options:
7979
* `appVersion` (Optional) Sets application version, which can be used to associate profiling information with the source code release.
8080
* `appEnvironment` (Optional) Used to differentiate applications in different environments.
8181
* `hostName` (Optional) By default, host name will be the OS hostname.
82-
* `autoProfiling` (Optional) If set to `false`, disables automatic profiling and reporting. `agent.profile()` and `agent.report(callback)` should be used instead. Useful for environments without support for timers or background tasks.
82+
* `autoProfiling` (Optional) If set to `false`, disables automatic profiling and reporting. Programmatic or manual profiling should be used instead. Useful for environments without support for timers or background tasks.
8383
* `debug` (Optional) Enables debug logging.
8484
* `cpuProfilerDisabled`, `allocationProfilerDisabled`, `asyncProfilerDisabled`, `errorProfilerDisabled` (Optional) Disables respective profiler when `true`.
8585
* `includeAgentFrames` (Optional) Set to `true` to not exclude agent stack frames from profiles.
8686

8787

8888
#### Programmatic profiling
8989

90-
Use `agent.profile()` to instruct the agent when to start and stop profiling. The agent decides if and which profiler is activated. Normally, this method should be used in repeating code, such as request or event handlers. Usage example:
90+
Use `agent.profile(name)` to instruct the agent when to start and stop profiling. The agent decides if and which profiler is activated. Normally, this method should be used in repeating code, such as request or event handlers. In addition to more precise profiling, timing information will also be reported for the profiled spans. Usage example:
9191

9292
```javascript
93-
const span = agent.profile();
93+
const span = agent.profile('span1');
9494

9595
// your code here
9696

@@ -100,6 +100,43 @@ span.stop();
100100
Is no callback is provided, `stop()` method returns a promise.
101101

102102

103+
#### Manual profiling
104+
105+
*Manual profiling should not be used in production!*
106+
107+
By default, the agent starts and stops profiling automatically. Manual profiling allows to start and stop profilers directly. It is suitable for profiling short-lived programs and should not be used for long-running production applications. Automatic profiling should be disabled with `autoProfiling: false`.
108+
109+
```javascript
110+
// Start CPU profiler.
111+
agent.startCpuProfiler();
112+
```
113+
114+
```javascript
115+
// Stop CPU profiler and report the recorded profile to the Dashboard.
116+
agent.stopCpuProfiler(callback);
117+
```
118+
119+
```javascript
120+
// Start async call profiler.
121+
agent.startAsyncProfiler();
122+
```
123+
124+
```javascript
125+
// Stop async call profiler and report the recorded profile to the Dashboard.
126+
agent.stopAsyncProfiler(callback);
127+
```
128+
129+
```javascript
130+
// Start heap allocation profiler.
131+
agent.startAllocationProfiler();
132+
```
133+
134+
```javascript
135+
// Stop heap allocation profiler and report the recorded profile to the Dashboard.
136+
agent.stopAllocationProfiler(callback);
137+
```
138+
139+
103140
#### Shutting down the agent
104141
*Optional*
105142

abi-map.json

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{"v4.0.0":"46","v4.1.0":"46","v4.1.1":"46","v4.1.2":"46","v4.2.0":"46","v4.2.1":"46","v4.2.2":"46","v4.2.3":"46","v4.2.4":"46","v4.2.5":"46","v4.2.6":"46","v4.3.0":"46","v4.3.1":"46","v4.3.2":"46","v4.4.0":"46","v4.4.1":"46","v4.4.2":"46","v4.4.3":"46","v4.4.4":"46","v4.4.5":"46","v4.4.6":"46","v4.4.7":"46","v4.5.0":"46","v4.6.0":"46","v4.6.1":"46","v4.6.2":"46","v4.7.0":"46","v4.7.1":"46","v4.7.2":"46","v4.7.3":"46","v4.8.0":"46","v4.8.1":"46","v4.8.2":"46","v4.8.3":"46","v4.8.4":"46","v5.0.0":"47","v5.1.0":"47","v5.1.1":"47","v5.10.0":"47","v5.10.1":"47","v5.11.0":"47","v5.11.1":"47","v5.12.0":"47","v5.2.0":"47","v5.3.0":"47","v5.4.0":"47","v5.4.1":"47","v5.5.0":"47","v5.6.0":"47","v5.7.0":"47","v5.7.1":"47","v5.8.0":"47","v5.9.0":"47","v5.9.1":"47","v6.0.0":"48","v6.1.0":"48","v6.10.0":"48","v6.10.1":"48","v6.10.2":"48","v6.10.3":"48","v6.11.0":"48","v6.11.1":"48","v6.11.2":"48","v6.2.0":"48","v6.2.1":"48","v6.2.2":"48","v6.3.0":"48","v6.3.1":"48","v6.4.0":"48","v6.5.0":"48","v6.6.0":"48","v6.7.0":"48","v6.8.0":"48","v6.8.1":"48","v6.9.0":"48","v6.9.1":"48","v6.9.2":"48","v6.9.3":"48","v6.9.4":"48","v6.9.5":"48","v7.0.0":"51","v7.1.0":"51","v7.10.0":"51","v7.10.1":"51","v7.2.0":"51","v7.2.1":"51","v7.3.0":"51","v7.4.0":"51","v7.5.0":"51","v7.6.0":"51","v7.7.1":"51","v7.7.2":"51","v7.7.3":"51","v7.7.4":"51","v7.8.0":"51","v7.9.0":"51","v8.0.0":"57","v8.1.0":"57","v8.1.1":"57","v8.1.2":"57","v8.1.3":"57","v8.1.4":"57","v8.2.0":"57","v8.2.1":"57","v8.3.0":"57","v8.4.0":"57","v8.5.0":"57","v8.6.0":"57","v8.7.0":"57","v8.8.0":"57","v8.8.1":"57","v8.9.0":"57","v8.9.1":"57","v8.9.2":"57","v8.9.3":"57","v8.9.4":"57","v8.10.0":"57","v8.11.0":"57","v8.11.1":"57","v9.0.0":"59","v9.1.0":"59","v9.2.0":"59","v9.2.1":"59","v9.3.0":"59","v9.4.0":"59","v9.5.0":"59","v9.6.0":"59","v9.6.1":"59","v9.7.0":"59","v9.7.1":"59","v9.8.0":"59","v9.9.0":"59","v9.10.0":"59","v9.10.1":"59","v9.11.0":"59","v9.11.1":"59"}
27.8 KB
Binary file not shown.
27.8 KB
Binary file not shown.
37.4 KB
Binary file not shown.
37.4 KB
Binary file not shown.
37.5 KB
Binary file not shown.
37.5 KB
Binary file not shown.
34.9 KB
Binary file not shown.
34.9 KB
Binary file not shown.
39.6 KB
Binary file not shown.
39.7 KB
Binary file not shown.
39.7 KB
Binary file not shown.
39.7 KB
Binary file not shown.
102 KB
Binary file not shown.
102 KB
Binary file not shown.
105 KB
Binary file not shown.
105 KB
Binary file not shown.
105 KB
Binary file not shown.
105 KB
Binary file not shown.

build-addons.js

+171
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,171 @@
1+
2+
const os = require('os');
3+
const fs = require('fs');
4+
const cp = require('child_process');
5+
6+
cp.execSync('npm update node-abi', {stdio: [0,1,2]});
7+
const nodeAbi = require('node-abi');
8+
9+
const versions= [
10+
"v4.0.0",
11+
"v4.1.0",
12+
"v4.1.1",
13+
"v4.1.2",
14+
"v4.2.0",
15+
"v4.2.1",
16+
"v4.2.2",
17+
"v4.2.3",
18+
"v4.2.4",
19+
"v4.2.5",
20+
"v4.2.6",
21+
"v4.3.0",
22+
"v4.3.1",
23+
"v4.3.2",
24+
"v4.4.0",
25+
"v4.4.1",
26+
"v4.4.2",
27+
"v4.4.3",
28+
"v4.4.4",
29+
"v4.4.5",
30+
"v4.4.6",
31+
"v4.4.7",
32+
"v4.5.0",
33+
"v4.6.0",
34+
"v4.6.1",
35+
"v4.6.2",
36+
"v4.7.0",
37+
"v4.7.1",
38+
"v4.7.2",
39+
"v4.7.3",
40+
"v4.8.0",
41+
"v4.8.1",
42+
"v4.8.2",
43+
"v4.8.3",
44+
"v4.8.4",
45+
"v5.0.0",
46+
"v5.1.0",
47+
"v5.1.1",
48+
"v5.10.0",
49+
"v5.10.1",
50+
"v5.11.0",
51+
"v5.11.1",
52+
"v5.12.0",
53+
"v5.2.0",
54+
"v5.3.0",
55+
"v5.4.0",
56+
"v5.4.1",
57+
"v5.5.0",
58+
"v5.6.0",
59+
"v5.7.0",
60+
"v5.7.1",
61+
"v5.8.0",
62+
"v5.9.0",
63+
"v5.9.1",
64+
"v6.0.0",
65+
"v6.1.0",
66+
"v6.10.0",
67+
"v6.10.1",
68+
"v6.10.2",
69+
"v6.10.3",
70+
"v6.11.0",
71+
"v6.11.1",
72+
"v6.11.2",
73+
"v6.2.0",
74+
"v6.2.1",
75+
"v6.2.2",
76+
"v6.3.0",
77+
"v6.3.1",
78+
"v6.4.0",
79+
"v6.5.0",
80+
"v6.6.0",
81+
"v6.7.0",
82+
"v6.8.0",
83+
"v6.8.1",
84+
"v6.9.0",
85+
"v6.9.1",
86+
"v6.9.2",
87+
"v6.9.3",
88+
"v6.9.4",
89+
"v6.9.5",
90+
"v7.0.0",
91+
"v7.1.0",
92+
"v7.10.0",
93+
"v7.10.1",
94+
"v7.2.0",
95+
"v7.2.1",
96+
"v7.3.0",
97+
"v7.4.0",
98+
"v7.5.0",
99+
"v7.6.0",
100+
"v7.7.1",
101+
"v7.7.2",
102+
"v7.7.3",
103+
"v7.7.4",
104+
"v7.8.0",
105+
"v7.9.0",
106+
"v8.0.0",
107+
"v8.1.0",
108+
"v8.1.1",
109+
"v8.1.2",
110+
"v8.1.3",
111+
"v8.1.4",
112+
"v8.2.0",
113+
"v8.2.1",
114+
"v8.3.0",
115+
"v8.4.0",
116+
"v8.5.0",
117+
"v8.6.0",
118+
"v8.7.0",
119+
"v8.8.0",
120+
"v8.8.1",
121+
"v8.9.0",
122+
"v8.9.1",
123+
"v8.9.2",
124+
"v8.9.3",
125+
"v8.9.4",
126+
"v8.10.0",
127+
"v8.11.0",
128+
"v8.11.1",
129+
"v9.0.0",
130+
"v9.1.0",
131+
"v9.2.0",
132+
"v9.2.1",
133+
"v9.3.0",
134+
"v9.4.0",
135+
"v9.5.0",
136+
"v9.6.0",
137+
"v9.6.1",
138+
"v9.7.0",
139+
"v9.7.1",
140+
"v9.8.0",
141+
"v9.9.0",
142+
"v9.10.0",
143+
"v9.10.1",
144+
"v9.11.0",
145+
"v9.11.1"
146+
];
147+
148+
149+
let abiMap = {};
150+
151+
let addonDir = `addons/${os.platform()}-${process.arch}`;
152+
if (!fs.existsSync(addonDir)) {
153+
fs.mkdirSync(addonDir);
154+
}
155+
156+
versions.forEach((version) => {
157+
let abi = nodeAbi.getAbi(version);
158+
let addonPath = `${addonDir}/stackimpact-addon-v${abi}.node`;
159+
160+
if (!fs.existsSync(addonPath)) {
161+
cp.execSync(`node-gyp rebuild --target=${version}`, {stdio: [0,1,2]});
162+
fs.copyFileSync('build/Release/stackimpact-addon.node', addonPath);
163+
}
164+
else {
165+
console.log(`Addon with ABI ${abi} exists, skipping.`);
166+
}
167+
168+
abiMap[version] = abi;
169+
});
170+
171+
fs.writeFileSync('abi-map.json', JSON.stringify(abiMap));

examples/lambda.js renamed to examples/aws-lambda/index.js

+1-13
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,11 @@
1-
const stackimpact = require('..');
1+
const stackimpact = require('../..');
22

33

44
const agent = stackimpact.start({
55
agentKey: process.env.AGENT_KEY,
66
appName: 'ExampleNodejsLambda',
77
appEnvironment: 'prod',
88
autoProfiling: false,
9-
cpuProfilerDisabled: false,
10-
allocationProfilerDisabled: false,
119
debug: true
1210
});
1311

@@ -43,13 +41,3 @@ exports.handler = function(event, context, callback) {
4341
callback(null, response);
4442
});
4543
};
46-
47-
48-
49-
// Simulate events.
50-
// Delete if deploying as lambda function.
51-
setInterval(() => {
52-
exports.handler({}, {}, () => {
53-
console.log('RequestResponse');
54-
});
55-
}, 1000);

examples/app.js renamed to examples/demo/app.js

+2-4
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
const fs = require('fs');
22
const http = require('http');
3-
const stackimpact = require('..');
3+
const stackimpact = require('../..');
44

55

66
// StackImpact agent initialization
@@ -9,8 +9,6 @@ let agent = stackimpact.start({
99
agentKey: process.env.AGENT_KEY,
1010
appName: 'ExampleNodejsApp',
1111
appVersion: '1.0.0',
12-
cpuProfilerDisabled: false,
13-
allocationProfilerDisabled: false,
1412
debug: true
1513
});
1614

@@ -101,7 +99,7 @@ function simulateProgrammaticProfiling() {
10199
setInterval(() => {
102100
let span = agent.profile();
103101

104-
for(let i = 0; i < usage * 300000; i++) {
102+
for(let i = 0; i < 100000; i++) {
105103
Math.random();
106104
}
107105

examples/manual/alloc.js

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
const stackimpact = require('../..');
2+
3+
4+
const agent = stackimpact.start({
5+
agentKey: process.env.AGENT_KEY,
6+
appName: 'MyNodeApp',
7+
appEnvironment: 'mydevenv',
8+
autoProfiling: false
9+
});
10+
11+
12+
function simulateMemAllocs() {
13+
let mem = [];
14+
15+
setInterval(() => {
16+
for(let i = 0; i < 1000000; i++) {
17+
obj = {'v': Math.random()};
18+
mem.push(obj);
19+
}
20+
}, 1000);
21+
}
22+
23+
agent.startAllocationProfiler();
24+
25+
simulateMemAllocs();
26+
27+
setTimeout(() => {
28+
agent.stopAllocationProfiler(() => {
29+
// profile reported
30+
process.exit();
31+
});
32+
}, 5000);

examples/manual/async.js

+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
const https = require('https');
2+
const stackimpact = require('../..');
3+
4+
5+
const agent = stackimpact.start({
6+
agentKey: process.env.AGENT_KEY,
7+
appName: 'MyNodeApp',
8+
appEnvironment: 'mydevenv',
9+
autoProfiling: false
10+
});
11+
12+
13+
function simulateAsyncWork() {
14+
setInterval(() => {
15+
var req = https.get('https://stackimpact.com', (res) => {
16+
});
17+
18+
req.on('error', function(err) {
19+
console.log(err.message);
20+
});
21+
}, 1000);
22+
}
23+
24+
agent.startAsyncProfiler();
25+
26+
simulateAsyncWork();
27+
28+
setTimeout(() => {
29+
agent.stopAsyncProfiler(() => {
30+
// profile reported
31+
process.exit();
32+
});
33+
}, 5000);

0 commit comments

Comments
 (0)