Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[DI] Add Sirun benchmark for Dynamic Instrumentation #5004

Merged
merged 1 commit into from
Jan 13, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions benchmark/sirun/debugger/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Dynamic Instrumentation Benchmarks

Benchmark the overhead on the instrumented application of different probe configurations.
46 changes: 46 additions & 0 deletions benchmark/sirun/debugger/app.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
'use strict'

// WARNING: CHANGES TO THIS FUNCTION WILL AFFECT THE LINE NUMBERS OF THE BREAKPOINTS

if (process.env.DD_DYNAMIC_INSTRUMENTATION_ENABLED === 'true') {
require('./start-devtools-client')
}

let n = 0

// Give the devtools client time to connect before doing work
setTimeout(doSomeWork, 250)

function doSomeWork (arg1 = 1, arg2 = 2) {
const data = getSomeData()
data.n = n
if (++n <= 500) {
setTimeout(doSomeWork, 1)
}
}

// Location to put dummy breakpoint that is never hit:
// eslint-disable-next-line no-unused-vars
function dummy () {
throw new Error('This line should never execute')
}

function getSomeData () {
const str = 'a'.repeat(1000)
const arr = Array.from({ length: 1000 }, (_, i) => i)

const data = {
foo: 'bar',
nil: null,
undef: undefined,
bool: true
}
data.recursive = data

for (let i = 0; i < 20; i++) {
data[`str${i}`] = str
data[`arr${i}`] = arr
}

return data
}
66 changes: 66 additions & 0 deletions benchmark/sirun/debugger/meta.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
{
"name": "debugger",
"cachegrind": false,
"iterations": 10,
"instructions": true,
"variants": {
"control": {
"service": "while true; do { echo -e 'HTTP/1.1 202 Accepted\r\n\r\n'; } | nc -l 8080 > /dev/null; done",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is just my curiosity: this looks useful for my future purposes too, but can you explain to me why is this "service" necessary? It seems to me like the tested app.js doesn't do any HTTP.

Copy link
Collaborator Author

@watson watson Jan 13, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A service is a secondary process that's booted up along side the main process being tested. This is just if the process being tested requires any accompanying process while running. In my case, I wanted to ensure that there were a dummy agent running on the same machine so that the process being tested didn't have to waste time retrying requests to the agent. The service process is automatically killed once the test is finished.

"run": "node app.js",
"run_with_affinity": "bash -c \"taskset -c $CPU_AFFINITY node app.js\"",
"env": {
"DD_DYNAMIC_INSTRUMENTATION_ENABLED": "false"
}
},
"enabled-but-breakpoint-not-hit": {
"service": "while true; do { echo -e 'HTTP/1.1 202 Accepted\r\n\r\n'; } | nc -l 8080 > /dev/null; done",
"run": "node app.js",
"run_with_affinity": "bash -c \"taskset -c $CPU_AFFINITY node app.js\"",
"baseline": "control",
"env": {
"DD_DYNAMIC_INSTRUMENTATION_ENABLED": "true",
"BREAKPOINT_FILE": "app.js",
"BREAKPOINT_LINE": "25"
}
},
"line-probe-without-snapshot": {
"service": "while true; do { echo -e 'HTTP/1.1 202 Accepted\r\n\r\n'; } | nc -l 8080 > /dev/null; done",
"run": "node app.js",
"run_with_affinity": "bash -c \"taskset -c $CPU_AFFINITY node app.js\"",
"baseline": "control",
"env": {
"DD_DYNAMIC_INSTRUMENTATION_ENABLED": "true",
"BREAKPOINT_FILE": "app.js",
"BREAKPOINT_LINE": "18"
}
},
"line-probe-with-snapshot-default": {
"service": "while true; do { echo -e 'HTTP/1.1 202 Accepted\r\n\r\n'; } | nc -l 8080 > /dev/null; done",
"run": "node app.js",
"run_with_affinity": "bash -c \"taskset -c $CPU_AFFINITY node app.js\"",
"baseline": "line-probe-without-snapshot",
"env": {
"DD_DYNAMIC_INSTRUMENTATION_ENABLED": "true",
"BREAKPOINT_FILE": "app.js",
"BREAKPOINT_LINE": "18",
"CAPTURE_SNAPSHOT": "true"
}
},
"line-probe-with-snapshot-minimal": {
"service": "while true; do { echo -e 'HTTP/1.1 202 Accepted\r\n\r\n'; } | nc -l 8080 > /dev/null; done",
"run": "node app.js",
"run_with_affinity": "bash -c \"taskset -c $CPU_AFFINITY node app.js\"",
"baseline": "line-probe-without-snapshot",
"env": {
"DD_DYNAMIC_INSTRUMENTATION_ENABLED": "true",
"BREAKPOINT_FILE": "app.js",
"BREAKPOINT_LINE": "18",
"CAPTURE_SNAPSHOT": "true",
"MAX_REFERENCE_DEPTH": "0",
"MAX_COLLECTION_SIZE": "0",
"MAX_FIELD_COUNT": "0",
"MAX_LENGTH": "9007199254740991"
}
}
}
}
31 changes: 31 additions & 0 deletions benchmark/sirun/debugger/start-devtools-client.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
'use strict'

const Config = require('../../../packages/dd-trace/src/config')
const { start } = require('../../../packages/dd-trace/src/debugger')
const { generateProbeConfig } = require('../../../packages/dd-trace/test/debugger/devtools_client/utils')

const breakpoint = {
file: process.env.BREAKPOINT_FILE,
line: process.env.BREAKPOINT_LINE
}
const config = new Config()
const rc = {
setProductHandler (product, cb) {
const action = 'apply'
const conf = generateProbeConfig(breakpoint, {
captureSnapshot: process.env.CAPTURE_SNAPSHOT === 'true',
capture: {
maxReferenceDepth: process.env.MAX_REFERENCE_DEPTH ? parseInt(process.env.MAX_REFERENCE_DEPTH, 10) : undefined,
maxCollectionSize: process.env.MAX_COLLECTION_SIZE ? parseInt(process.env.MAX_COLLECTION_SIZE, 10) : undefined,
maxFieldCount: process.env.MAX_FIELD_COUNT ? parseInt(process.env.MAX_FIELD_COUNT, 10) : undefined,
maxLength: process.env.MAX_LENGTH ? parseInt(process.env.MAX_LENGTH, 10) : undefined
}
})
const id = 'id'
const ack = () => {}

cb(action, conf, id, ack)
}
}

start(config, rc)
Loading