Skip to content

Commit 16c0275

Browse files
committed
Testing
1 parent 69d45f6 commit 16c0275

File tree

3 files changed

+90
-6
lines changed

3 files changed

+90
-6
lines changed
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
const performance = require('perf_hooks').performance
2+
3+
const EVENT_COUNT = parseInt(process.argv[2])
4+
require('dd-trace').init().profilerStarted().then(() => {
5+
const EventSource = require('dd-trace/packages/dd-trace/src/profiling/profilers/events.js')
6+
const template = {
7+
entryType: 'dns',
8+
duration: 10,
9+
name: 'lookup',
10+
_ddSpanId: '1234567890abcdef',
11+
_ddRootSpanId: 'abcdef1234567890',
12+
detail: {
13+
hostname: 'example.com'
14+
}
15+
}
16+
for (let i = 0; i < EVENT_COUNT; i++) {
17+
EventSource.emitTestEvent({ startTime: performance.now(), ...template })
18+
}
19+
})

integration-tests/profiler/profiler.spec.js

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -454,6 +454,33 @@ describe('profiler', () => {
454454
assert.equal(endpoints.size, 3, encoded)
455455
})
456456

457+
it('number of events is limited', async () => {
458+
const threads = 1
459+
const uploadPeriodSec = 10
460+
const samplingPeriodMs = 1000 / 99
461+
// Recreates getMaxSamples from packages/dd-trace/src/profiling/profilers/events.js
462+
const maxEvents = Math.floor((threads + 2) * uploadPeriodSec * 1000 / samplingPeriodMs)
463+
464+
// Test will try to force maxEvents + 10 events, we'll assert that only maxEvents are captured.
465+
const proc = fork(path.join(cwd, 'profiler/eventlimits.js'), [String(maxEvents + 10)], {
466+
cwd,
467+
env: {
468+
DD_PROFILING_EXPORTERS: 'file',
469+
DD_PROFILING_ENABLED: 1,
470+
DD_INTERNAL_PROFILING_TIMELINE_SAMPLING_ENABLED: 0, // capture all events
471+
DD_TRACE_AGENT_PORT: agent.port,
472+
TESTING_PROFILING_EVENTS: 'true', // enable test event source
473+
DD_PROFILING_UPLOAD_PERIOD: String(uploadPeriodSec),
474+
UV_THREADPOOL_SIZE: String(threads)
475+
}
476+
})
477+
478+
await processExitPromise(proc, TIMEOUT)
479+
480+
const { profile, encoded } = await getLatestProfile(cwd, /^events_.+\.pprof$/)
481+
assert.equal(profile.sample.length, maxEvents, encoded)
482+
})
483+
457484
it('fs timeline events work', async () => {
458485
const fsEvents = await gatherFilesystemTimelineEvents(cwd, 'profiler/fstest.js', agent.port)
459486
assert.equal(fsEvents.length, 6)

packages/dd-trace/src/profiling/profilers/events.js

Lines changed: 44 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,11 @@ const { performance, constants, PerformanceObserver } = require('perf_hooks')
44
const { END_TIMESTAMP_LABEL, SPAN_ID_LABEL, LOCAL_ROOT_SPAN_ID_LABEL, encodeProfileAsync } = require('./shared')
55
const { Function, Label, Line, Location, Profile, Sample, StringTable, ValueType } = require('pprof-format')
66
const { availableParallelism, effectiveLibuvThreadCount } = require('../libuv-size')
7+
const dc = require('dc-polyfill')
8+
9+
const testEventChannel = ['true','1'].includes(process.env.TESTING_PROFILING_EVENTS)
10+
? dc.channel('dd-trace:profiling:events-test')
11+
: undefined
712

813
// perf_hooks uses millis, with fractional part representing nanos. We emit nanos into the pprof file.
914
const MS_TO_NS = 1_000_000
@@ -363,6 +368,27 @@ class DatadogInstrumentationEventSource {
363368
}
364369
}
365370

371+
class TestEventSource {
372+
constructor (eventHandler) {
373+
this.eventHandler = eventHandler
374+
this.started = false
375+
}
376+
377+
start () {
378+
if (!this.started) {
379+
testEventChannel.subscribe(this.eventHandler)
380+
this.started = true
381+
}
382+
}
383+
384+
stop () {
385+
if (this.started) {
386+
testEventChannel.unsubscribe(this.eventHandler)
387+
this.started = false
388+
}
389+
}
390+
}
391+
366392
class CompositeEventSource {
367393
constructor (sources) {
368394
this.sources = sources
@@ -430,15 +456,21 @@ class EventsProfiler {
430456
}
431457
}
432458

433-
this.eventSource = options.codeHotspotsEnabled
459+
const eventSources = options.codeHotspotsEnabled
434460
// Use Datadog instrumentation to collect events with span IDs. Still use
435461
// Node API for GC events.
436-
? new CompositeEventSource([
437-
new DatadogInstrumentationEventSource(eventHandler, eventFilter),
438-
new NodeApiEventSource(filteringEventHandler, ['gc'])
439-
])
462+
? [
463+
new DatadogInstrumentationEventSource(eventHandler, eventFilter),
464+
new NodeApiEventSource(filteringEventHandler, ['gc']),
465+
]
440466
// Use Node API instrumentation to collect events without span IDs
441-
: new NodeApiEventSource(filteringEventHandler)
467+
: [
468+
new NodeApiEventSource(filteringEventHandler)
469+
]
470+
if (testEventChannel !== undefined) {
471+
eventSources.push(new TestEventSource(filteringEventHandler))
472+
}
473+
this.eventSource = new CompositeEventSource(eventSources)
442474
}
443475

444476
start () {
@@ -461,6 +493,12 @@ class EventsProfiler {
461493
encode (profile) {
462494
return encodeProfileAsync(profile())
463495
}
496+
497+
static emitTestEvent (event) {
498+
if (testEventChannel !== undefined) {
499+
testEventChannel.publish(event)
500+
}
501+
}
464502
}
465503

466504
module.exports = EventsProfiler

0 commit comments

Comments
 (0)