Skip to content

Commit 829fea3

Browse files
committed
[GR-37636] Declarative position of insight context.
PullRequest: graal/11980
2 parents 10c723a + a2d863e commit 829fea3

File tree

21 files changed

+1233
-168
lines changed

21 files changed

+1233
-168
lines changed

docs/tools/insight/Insight-Manual.md

Lines changed: 109 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ This provides ultimate insights into execution and behavior of one's application
2424
- [Insight into C Code](#insight-into-c-code)
2525
- [Inspecting Values](#inspecting-values)
2626
- [Modifying Local Variables](#modifying-local-variables)
27+
- [Insight to a Specific Location](#insight-to-a-specific-location)
2728
- [Delaying Insight Initialization in Node.JS](#delaying-insight-initialization-in-nodejs)
2829
- [Handling Exceptions](#handling-exceptions)
2930
- [Intercepting and Altering Execution](#intercepting-and-altering-execution)
@@ -216,24 +217,38 @@ It is possible to write GraalVM Insight scripts in Python.
216217
Such insights can be applied to programs written in Python or any other language.
217218

218219
Here is an example of a script that prints out value of variable `n` when a function `minusOne` is called.
219-
Save this code to the `agent-fib.js` file:
220+
Save this code to the `agent.py` file:
221+
222+
```python
223+
def onEnter(ctx, frame):
224+
print(f"minusOne {frame.n}")
225+
226+
class At:
227+
sourcePath = ".*agent-fib.js"
228+
229+
class Roots:
230+
roots = True
231+
at = At()
232+
rootNameFilter = "minusOne"
233+
234+
insight.on("enter", onEnter, Roots())
235+
```
236+
This code uses a declarative specification of source location introduced in GraalVM 22.2. Use a dynamic `sourceFilter` with older GraalVM versions:
220237

221238
```python
222239
def onEnter(ctx, frame):
223240
print(f"minusOne {frame.n}")
224241

225242
class Roots:
226243
roots = True
244+
rootNameFilter = "minusOne"
227245

228246
def sourceFilter(self, src):
229247
return src.name == "agent-fib.js"
230248

231-
def rootNameFilter(self, n):
232-
return n == "minusOne"
233-
234249
insight.on("enter", onEnter, Roots())
235250
```
236-
Apply this script to, for example, a JavaScript application using the following command:
251+
Apply this script to [agent-fib.js](../../../vm/tests/all/agentscript/agent-fib.js) using the following command:
237252

238253
```bash
239254
`js --polyglot --insight=agent.py agent-fib.js`
@@ -257,35 +272,55 @@ insight.on("source", -> (env) {
257272
puts "Ruby: observed loading of #{env.name}"
258273
})
259274
puts("Ruby: Hooks are ready!")
275+
```
276+
277+
Launch a Node.js application and instrument it with the Ruby script:
278+
279+
```bash
280+
graalvm/bin/node --js.print --experimental-options --polyglot --insight=source-tracing.rb agent-fib.js
281+
Ruby: Initializing GraalVM Insight script
282+
Ruby: Hooks are ready!
283+
Ruby: observed loading of node:internal/errors
284+
Ruby: observed loading of node:internal/util
285+
Ruby: observed loading of node:events
286+
....
287+
Ruby: observed loading of node:internal/modules/run_main
288+
Ruby: observed loading of <...>/agent-fib.js
289+
Three is the result 3
290+
```
260291

292+
To track variable values, create `agent.rb` script:
293+
```ruby
294+
insight.on("enter", -> (ctx, frame) {
295+
puts("minusOne #{frame.n}")
296+
}, {
297+
roots: true,
298+
rootNameFilter: "minusOne",
299+
at: {
300+
sourcePath: ".*agent-fib.js"
301+
}
302+
})
303+
```
304+
This code uses a declarative specification of source location introduced in GraalVM 22.2. Use a dynamic `sourceFilter` with older GraalVM versions:
305+
```ruby
261306
insight.on("enter", -> (ctx, frame) {
262307
puts("minusOne #{frame.n}")
263308
}, {
264309
roots: true,
265310
rootNameFilter: "minusOne",
266311
sourceFilter: -> (src) {
267-
return src.name == "agent-fib.js"
312+
return src.name == Dir.pwd+"/agent-fib.js"
268313
}
269314
})
270315
```
271316

272-
The above Ruby script example prints out value of variable `n` when a function `minusOne` in the `agent-fib.js` program is called.
273-
Launch a Node.js application and instrument it with the Ruby script:
274-
317+
The above Ruby script example prints out value of variable `n` when a function `minusOne` in the [agent-fib.js](../../../vm/tests/all/agentscript/agent-fib.js) program is called:
275318
```bash
276-
graalvm/bin/node --js.print --polyglot --insight=agent-ruby.rb agent-fib.js
277-
Ruby: Initializing GraalVM Insight script
278-
Ruby: Hooks are ready!
279-
Ruby: observed loading of internal/per_context/primordials.js
280-
Ruby: observed loading of internal/per_context/setup.js
281-
Ruby: observed loading of internal/per_context/domexception.js
282-
....
283-
Ruby: observed loading of internal/modules/cjs/loader.js
284-
Ruby: observed loading of vm.js
285-
Ruby: observed loading of fs.js
286-
Ruby: observed loading of internal/fs/utils.js
287-
Ruby: observed loading of [eval]-wrapper
288-
Ruby: observed loading of [eval]
319+
graalvm/bin/node --js.print --experimental-options --polyglot --insight=agent.rb agent-fib.js
320+
minusOne 4
321+
minusOne 3
322+
minusOne 2
323+
minusOne 2
289324
Three is the result 3
290325
```
291326

@@ -462,6 +497,58 @@ GraalVM Insight `enter` and `return` hooks can only modify existing variables.
462497
They cannot introduce new ones.
463498
Attempts to do so yield an exception.
464499

500+
## Insight to a Specific Location
501+
502+
To get to variables at a specific code location, the `at` object may have not only one of the mandatory source specifications:
503+
a `sourcePath` property with the regular expression matching the source file path, or `sourceURI` property with string representation of the source URI.
504+
There can also be an optional `line` and/or `column` specified. Let's have a `distance.js` source file:
505+
```js
506+
(function(x, y) {
507+
let x2 = x*x;
508+
let y2 = y*y;
509+
let d = Math.sqrt(x2 + y2);
510+
for (let i = 0; i < d; i++) {
511+
// ...
512+
}
513+
return d;
514+
})(3, 4);
515+
```
516+
517+
Then we can apply following `distance-trace.js` insight script to get values of variables:
518+
```js
519+
insight.on('enter', function(ctx, frame) {
520+
print("Squares: " + frame.x2 + ", " + frame.y2);
521+
}, {
522+
statements: true,
523+
at: {
524+
sourcePath: ".*distance.js",
525+
line: 4
526+
}
527+
});
528+
529+
insight.on('enter', function(ctx, frame) {
530+
print("Loop var i = " + frame.i);
531+
}, {
532+
expressions: true,
533+
at: {
534+
sourcePath: ".*distance.js",
535+
line: 5,
536+
column: 21
537+
}
538+
});
539+
```
540+
That gives us:
541+
```bash
542+
graalvm/bin/js --insight=distance-trace.js distance.js
543+
Squares: 9, 16
544+
Loop var i = 0
545+
Loop var i = 1
546+
Loop var i = 2
547+
Loop var i = 3
548+
Loop var i = 4
549+
Loop var i = 5
550+
```
551+
465552
## Delaying Insight Initialization in Node.JS
466553

467554
GraalVM Insight can be used in any GraalVM language runtime, including the `node` implementation.

docs/tools/insight/Insight-Tracing.md

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,9 @@ let initialize = function(tracer) {
4040
}, {
4141
roots: true,
4242
rootNameFilter: 'emit',
43-
sourceFilter: src => src.name === 'events.js'
43+
at: {
44+
sourcePath: '.*events.js'
45+
}
4446
});
4547

4648
insight.on('return', function(ctx, frame) {
@@ -54,7 +56,9 @@ let initialize = function(tracer) {
5456
}, {
5557
roots: true,
5658
rootNameFilter: 'end',
57-
sourceFilter: src => src.name === '_http_outgoing.js'
59+
at: {
60+
sourcePath: '.*_http_outgoing.js'
61+
}
5862
});
5963
console.log('agent: ready');
6064
};

0 commit comments

Comments
 (0)